200709.1 · 9ee06d0f7d175ea76e0d917d79c23a928a95ba6d
released 2.4.0 - added ug command & ugrep --config to use config files; --help [WHAT]; improved AVX2 detection for optimization
reading declarations
@@ -8,35 +8,53 @@ all-local: cp2bin .PHONY: cp2bin -# to copy the ugrep binary to ugrep/bin (joins ugrep.exe that's already there)-cp2bin: $(top_builddir)/src/ugrep- -mkdir -p $(top_builddir)/bin- -cp -f $< $(top_builddir)/bin+# to copy the ugrep binary to the local ugrep/bin/ugrep and link ugrep/bin/ug+cp2bin: $(top_builddir)/src/ugrep$(EXEEXT)+ mkdir -p $(top_builddir)/bin; \+ cp -f $< $(top_builddir)/bin/ugrep$(EXEEXT); \+ cd $(top_builddir)/bin; \+ rm -f ug$(EXEEXT); \+ $(LN_S) ugrep$(EXEEXT) ug$(EXEEXT) @echo @echo "OK" @echo +install-exec-hook:+ rm -f $(DESTDIR)$(bindir)/ug$(EXEEXT)+ cd $(DESTDIR)$(bindir) && $(LN_S) ugrep$(EXEEXT) ug$(EXEEXT)+ install-data-hook:- (mkdir -p $(DESTDIR)$(datadir)/ugrep; \- cp -rf patterns $(DESTDIR)$(datadir)/ugrep/)+ mkdir -p $(DESTDIR)$(datadir)/ugrep && \+ cp -rf patterns $(DESTDIR)$(datadir)/ugrep/+ cd $(DESTDIR)$(mandir)/man1; \+ rm -f ug.1; \+ $(LN_S) ugrep.1 ug.1 @echo " ______________________________________________________ "; \ echo "| |"; \ echo "| You have successfully built and installed ugrep. |"; \ echo "| |"; \- echo "| You can use the ugrep command to search files. |"; \+ echo "| You can use the ugrep & ug commands to search files. |"; \+ echo "| |"; \+ echo "| The ugrep command is for batch use, whereas the ug |"; \+ echo "| command is intended for interactive searches using |"; \+ echo "| a .ugrep configuration file with your preferences, |"; \+ echo "| located in the working directory or home directory. |"; \+ echo "| Run 'ug --save-config' to create a .ugrep file. |"; \ echo "| |"; \ echo "| Useful aliases to consider: |"; \- echo "| alias ug = 'ugrep' |"; \- echo "| alias uq = 'ugrep -Q' |"; \- echo "| alias ux = 'ugrep -UX' |"; \- echo "| alias uz = 'ugrep -z' |"; \+ echo "| alias uq = 'ug -Q' |"; \+ echo "| alias ux = 'ug -UX' |"; \+ echo "| alias uz = 'ug -z' |"; \ echo "| alias grep = 'ugrep -G' |"; \ echo "| alias egrep = 'ugrep -E' |"; \ echo "| alias fgrep = 'ugrep -F' |"; \- echo "| alias xgrep = 'ugrep -W' |"; \+ echo "| alias pgrep = 'ugrep -P' |"; \+ echo "| alias xgrep = 'ugrep -UX' |"; \ echo "| alias zgrep = 'ugrep -zG' |"; \ echo "| alias zegrep = 'ugrep -zE' |"; \ echo "| alias zfgrep = 'ugrep -zF' |"; \+ echo "| alias zpgrep = 'ugrep -zP' |"; \+ echo "| alias zxgrep = 'ugrep -zUX' |"; \ echo "| alias xdump = 'ugrep -X \"\"' |"; \ echo "| |"; \ echo "| Thank you for using ugrep! |"; \@@ -44,6 +62,10 @@ install-data-hook: echo "| https://github.com/Genivia/ugrep |"; \ echo "|______________________________________________________|"; +uninstall-hook:+ rm -f $(DESTDIR)$(bindir)/ug$(EXEEXT)+ rm -rf $(DESTDIR)$(datadir)/ugrep+ .PHONY: test test: $(top_builddir)/src/ugrep
@@ -276,6 +276,7 @@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@+LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@@@ -810,7 +811,8 @@ install-dvi: install-dvi-recursive install-dvi-am: install-exec-am:-+ @$(NORMAL_INSTALL)+ $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-recursive install-html-am:@@ -850,11 +852,12 @@ ps: ps-recursive ps-am: uninstall-am: uninstall-man-+ @$(NORMAL_INSTALL)+ $(MAKE) $(AM_MAKEFLAGS) uninstall-hook uninstall-man: uninstall-man1 .MAKE: $(am__recursive_targets) all install-am install-data-am \- install-strip+ install-exec-am install-strip uninstall-am .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ am--refresh check check-am clean clean-cscope clean-generic \@@ -864,14 +867,14 @@ uninstall-man: uninstall-man1 distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-data-hook install-dvi \- install-dvi-am install-exec install-exec-am install-html \- install-html-am install-info install-info-am install-man \- install-man1 install-pdf install-pdf-am install-ps \+ install-dvi-am install-exec install-exec-am install-exec-hook \+ install-html install-html-am install-info install-info-am \+ install-man install-man1 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am \- uninstall-man uninstall-man1+ uninstall-hook uninstall-man uninstall-man1 .PRECIOUS: Makefile @@ -880,35 +883,53 @@ all-local: cp2bin .PHONY: cp2bin -# to copy the ugrep binary to ugrep/bin (joins ugrep.exe that's already there)-cp2bin: $(top_builddir)/src/ugrep- -mkdir -p $(top_builddir)/bin- -cp -f $< $(top_builddir)/bin+# to copy the ugrep binary to the local ugrep/bin/ugrep and link ugrep/bin/ug+cp2bin: $(top_builddir)/src/ugrep$(EXEEXT)+ mkdir -p $(top_builddir)/bin; \+ cp -f $< $(top_builddir)/bin/ugrep$(EXEEXT); \+ cd $(top_builddir)/bin; \+ rm -f ug$(EXEEXT); \+ $(LN_S) ugrep$(EXEEXT) ug$(EXEEXT) @echo @echo "OK" @echo +install-exec-hook:+ rm -f $(DESTDIR)$(bindir)/ug$(EXEEXT)+ cd $(DESTDIR)$(bindir) && $(LN_S) ugrep$(EXEEXT) ug$(EXEEXT)+ install-data-hook:- (mkdir -p $(DESTDIR)$(datadir)/ugrep; \- cp -rf patterns $(DESTDIR)$(datadir)/ugrep/)+ mkdir -p $(DESTDIR)$(datadir)/ugrep && \+ cp -rf patterns $(DESTDIR)$(datadir)/ugrep/+ cd $(DESTDIR)$(mandir)/man1; \+ rm -f ug.1; \+ $(LN_S) ugrep.1 ug.1 @echo " ______________________________________________________ "; \ echo "| |"; \ echo "| You have successfully built and installed ugrep. |"; \ echo "| |"; \- echo "| You can use the ugrep command to search files. |"; \+ echo "| You can use the ugrep & ug commands to search files. |"; \+ echo "| |"; \+ echo "| The ugrep command is for batch use, whereas the ug |"; \+ echo "| command is intended for interactive searches using |"; \+ echo "| a .ugrep configuration file with your preferences, |"; \+ echo "| located in the working directory or home directory. |"; \+ echo "| Run 'ug --save-config' to create a .ugrep file. |"; \ echo "| |"; \ echo "| Useful aliases to consider: |"; \- echo "| alias ug = 'ugrep' |"; \- echo "| alias uq = 'ugrep -Q' |"; \- echo "| alias ux = 'ugrep -UX' |"; \- echo "| alias uz = 'ugrep -z' |"; \+ echo "| alias uq = 'ug -Q' |"; \+ echo "| alias ux = 'ug -UX' |"; \+ echo "| alias uz = 'ug -z' |"; \ echo "| alias grep = 'ugrep -G' |"; \ echo "| alias egrep = 'ugrep -E' |"; \ echo "| alias fgrep = 'ugrep -F' |"; \- echo "| alias xgrep = 'ugrep -W' |"; \+ echo "| alias pgrep = 'ugrep -P' |"; \+ echo "| alias xgrep = 'ugrep -UX' |"; \ echo "| alias zgrep = 'ugrep -zG' |"; \ echo "| alias zegrep = 'ugrep -zE' |"; \ echo "| alias zfgrep = 'ugrep -zF' |"; \+ echo "| alias zpgrep = 'ugrep -zP' |"; \+ echo "| alias zxgrep = 'ugrep -zUX' |"; \ echo "| alias xdump = 'ugrep -X \"\"' |"; \ echo "| |"; \ echo "| Thank you for using ugrep! |"; \@@ -916,6 +937,10 @@ install-data-hook: echo "| https://github.com/Genivia/ugrep |"; \ echo "|______________________________________________________|"; +uninstall-hook:+ rm -f $(DESTDIR)$(bindir)/ug$(EXEEXT)+ rm -rf $(DESTDIR)$(datadir)/ugrep+ .PHONY: test test: $(top_builddir)/src/ugrep
@@ -12,7 +12,9 @@ Search for anything in everything... ultra fast - Ultra fast with new match algorithms, easily beating grep, ripgrep, silver searcher, hyperscan, sift, etc. see [performance benchmarks](#speed) -- User-friendly with sensible defaults and shortcuts for common grep options+- User-friendly with sensible defaults and customizable [configuration files](#config) used by the `ug` command (which is the same as `ugrep --config`)++ ug ... ugrep --config ... - Interactive [query UI](#query), press F1 or CTRL-Z for help @@ -104,6 +106,7 @@ Table of contents - [Examples](#examples) - [Advanced examples](#advanced) - [Displaying helpful info](#help)+ - [Configuration files](#config) - [Interactive search with -Q](#query) - [Recursively list matching files with -l, -R, -r, --depth, -g, -O, and -t](#recursion) - [Search this but not that with -v, -e, -N, -f, -L, -w, -x](#not)@@ -125,9 +128,9 @@ Table of contents - [Displaying file, line, column, and byte offset info with -H, -n, -k, -b, and -T](#fields) - [Displaying colors with --color and paging the output with --pager](#color) - [Output matches in JSON, XML, CSV, C++](#json)- - [Customized output with --format](#format)+ a [Customized output with --format](#format) - [Replacing matches with --format backreferences to group captures](#replace)- - [Limiting the number of matches with -m, --depth, --max-files, and --range](#max)+ - [Limiting the number of matches with -1,-2...-9, -K, -m, and --max-files](#max) - [Matching empty patterns with --empty](#empty) - [Case-insensitive matching with -i and -j](#case) - [Sort files by name, best match, size, and time](#sort)@@ -152,16 +155,22 @@ Install the latest **ugrep** with [Homebrew](https://brew.sh): $ brew install https://raw.githubusercontent.com/Genivia/ugrep/master/Formula/ugrep.rb +This installs the `ugrep` and `ug` commands, where `ug` is the same as `ugrep`+but also loads the default configuration file .ugrep when present.+ ### Windows -Download the full-featured ugrep executable as a release artifact from+Download the full-featured `ugrep.exe` executable as release artifacts from <https://github.com/Genivia/ugrep/releases> -To add `ugrep.exe` to your execution path: go to *Settings* and search for-"Path" in *Find a Setting*. Select *environment variables* -> *Path* -> *New*-and add the directory where you placed `ugrep.exe`.+Copy `ugrep.exe` to `ug.exe` if you want the short interactive `ug` command.++Add `ugrep.exe` and `ug.exe` to your execution path: go to *Settings* and+search for "Path" in *Find a Setting*. Select *environment variables* ->+*Path* -> *New* and add the directory where you placed the `ugrep.exe` and+`ug.exe` executables. -On using `ugrep.exe` from the Windows command line:+Some notes on using `ugrep.exe` and `ug.exe` from the Windows command line: - when quoting patterns and arguments on the command line, do not use single `'` quotes but use `"` instead; most Windows command utilities consider the single `'` quotes part of the command-line argument!@@ -237,10 +246,13 @@ Choices for defaults include: - `--with-grep-colors` the default colors if `GREP_COLORS` is not defined - `--help` display build options -After the build completes, copy `ugrep/bin/ugrep` to a convenient location, for-example in your `~/bin` directory.+After the build completes, copy `ugrep/bin/ugrep` and `ugrep/bin/ug` to a+convenient location, for example in your `~/bin` directory. -Or you may want to install the `ugrep` command and its manual page with:+Note that `ug` is the same as `ugrep` but also loads the default configuration+file .ugrep when present.++You may want to install the `ugrep` and `ug` commands and its manual page with: $ sudo make install @@ -284,10 +296,10 @@ Performance comparisons ----------------------- Ugrep is multi-threaded and uses clever lock-free job queue stealing for-optimized load balancing. We also optimized regex matching with AVX, SSE2, and-ARM NEON/AArch64 instructions. Compressed files are decompressed concurrently-while searching. Asynchronous IO is used for efficient concurrent searching-and output.+optimized load balancing. We also optimized regex matching with AVX2/512BW,+SSE2, and ARM NEON/AArch64 instructions. Compressed files are decompressed+concurrently while searching. Asynchronous IO is used for efficient concurrent+searching and output. ### Benchmarks @@ -308,7 +320,7 @@ T10 | `GREP -ro '#[[:space:]]*include[[:space:]]+"[^"]+"' -Oh,hpp,cpp` | multi- T11 | `GREP -ro '#[[:space:]]*include[[:space:]]+"[^"]+"' -Oh,hpp,cpp` | same as T10 but single-threaded T12 | `GREP -z -Fc word word*.gz` | count `word` in 6 compressed files of 1MB to 3MB each -Note: T10 and T11 use **ugrep** option `-Oh,hpp,cpp` to restrict the search to+Note: T10 and T11 use `ugrep` option `-Oh,hpp,cpp` to restrict the search to files with extensions `.h`, `.hpp`, and `.cpp`, which should be formulated with GNU/BSD/PCRGE grep as `--include='*.h' --include='*.hpp' --include='*.cpp'`, with silver searcher as `-G '.*\.(h|hpp|cpp)'` requiring `--search-binary` to@@ -462,7 +474,7 @@ Ugrep versus other greps ### Equivalence to GNU grep and BSD grep -**Ugrep** is equivalent to GNU/BSD grep when the following options are used:+**ugrep** is equivalent to GNU/BSD grep when the following options are used: grep = ugrep --sort -G -U -Y -. -Dread -dread egrep = ugrep --sort -E -U -Y -. -Dread -dread@@ -472,26 +484,26 @@ Ugrep versus other greps zegrep = ugrep --sort -E -U -Y -z -. -Dread -dread zfgrep = ugrep --sort -F -U -Y -z -. -Dread -dread -Where:+where: - `--sort` specifies output sorted by pathname, showing sorted matching files first followed by sorted recursive matches in subdirectories. Otherwise, matching files are reported in no particular order to improve performance; - `-U` disables Unicode pattern matching, so for example the pattern `\xa3` matches byte A3 instead of the Unicode code point U+00A3 represented by the- UTF-8 sequence C2 A3. By default in ugrep, `\xa3` matches U+00A3.+ UTF-8 sequence C2 A3. By default in ugrep, `\xa3` matches U+00A3. We do not+ recommend to use `-U` for text pattern searches, only for binary searches. - `-Y` enables empty matches, so for example the pattern `a*` matches every line instead of a sequence of `a`'s. By default in ugrep, the pattern `a*`- matches a sequence of `a`'s. Moreover, by default the pattern `a*b*c*`- matches what it is supposed to match. See [improvements](#improvements).+ matches a sequence of `a`'s. Moreover, in ugrep the pattern `a*b*c*` matches+ what it is supposed to match by default. See [improvements](#improvements). - `-.` searches hidden files (dotfiles). By default, hidden files are ignored- like most Unix utilities such as `ls`.+ by defaullt, like most Unix utilities such as `ls`. - `-Dread` and `-dread` are the GNU/BSD grep defaults but are not recommended, see [improvements](#improvements) for an explanation. -When the **ugrep** executable is renamed to `grep` and so on, then these-options show above are also in effect except for `-U` to permit Unicode-matching.+When the `ugrep` executable is renamed to `grep` and so on, then these options+shown above are also in effect except for `-U` to permit Unicode matching. Note that the defaults of some grep options may differ to make **ugrep** more user friendly, see [notable improvements over grep](#improvements).@@ -504,21 +516,22 @@ user friendly, see [notable improvements over grep](#improvements). Commonly-used aliases to add to `.bashrc` to increase productivity: - alias ug = 'ugrep' # short & quick text pattern search- alias uq = 'ugrep -Q' # short & quick query UI (interactive)- alias ux = 'ugrep -UX' # short & quick binary pattern search- alias uz = 'ugrep -z' # short & quick compressed files and archives search+ alias uq = 'ug -Q' # short & quick query UI (interactive, uses .ugrep config)+ alias ux = 'ug -UX' # short & quick binary pattern search (uses .ugrep config)+ alias uz = 'ug -z' # short & quick compressed files and archives search (uses .ugrep config) - alias ugit = 'ugrep -R --ignore-files' # works like git-grep+ alias ugit = 'ug -R --ignore-files' # works like git-grep, define your preferences in .ugrep config alias grep = 'ugrep -G' # search with basic regular expressions (BRE) alias egrep = 'ugrep -E' # search with extended regular expressions (ERE) alias fgrep = 'ugrep -F' # find string(s)+ alias pgrep = 'ugrep -P' # search with Perl regular expressions alias xgrep = 'ugrep -W' # search (ERE) and output text or hex for binary - alias zgrep = 'ugrep -zG' # search compressed files and archives (BRE)- alias zegrep = 'ugrep -zE' # search compressed files and archives (ERE)+ alias zgrep = 'ugrep -zG' # search compressed files and archives with BRE+ alias zegrep = 'ugrep -zE' # search compressed files and archives with ERE alias zfgrep = 'ugrep -zF' # find string(s) in compressed files and/or archives+ alias zpgrep = 'ugrep -zP' # search compressed files and archives with Perl regular expressions alias zxgrep = 'ugrep -zW' # search (ERE) compressed files/archives and output text or hex for binary alias xdump = 'ugrep -X ""' # hexdump files without searching@@ -617,6 +630,16 @@ Tutorial ### Examples +To perform a search using a configuration file `.ugrep` placed in the working+directory or home directory (`ug` is the same as `ugrep --config`):++ ug PATTERN FILE...++To save a default configuration file to the working directory (edit this file+in your home directory to customize your preferences for `ug` defaults):++ ug --save-config+ To search the working directory and recursively deeper for `main` (note that `-R` recurse symlinks is enabled by default if no file arguments are specified):@@ -805,12 +828,95 @@ To show a help page: ugrep --help +To show options that mention `WHAT`:++ ugrep --help WHAT+ To show a list of `-t TYPES` option values: ugrep -tlist 🔝 [Back to table of contents](#toc) +<a name="config"/>++### Configuration files++ --config[=FILE], ---[FILE]+ Use configuration FILE. The default FILE is `.ugrep'. The working+ directory is checked first for FILE, then the home directory. The+ options specified in the configuration FILE are parsed first,+ followed by the remaining options on the command line.+ --save-config[=FILE]+ Save configuration FILE. By default `.ugrep' is saved. If FILE is+ a `-', write the configuration to standard output.++#### The ug command versus the ugrep command++The `ug` command is intended for context-dependent interactive searching and is+equivalent to the `grep --config` command to load the default configuration+file `.ugrep`, when present in the working directory or, when not found, in the+home directory:++ ug ...+ ugrep --config ...++A configuration file contains `NAME=VALUE` pairs per line, where `NAME` is the+name of a long option (without `--`) and `=VALUE` is an argument, which is+optional and may be omitted depending on the option. Empty lines and lines+starting with a `#` are ignored:++ # Color scheme+ colors=cx=hb:ms=hic:mc=hi+cB:fn=hi+c+K:ln=hg:cn=hg:bn=hg:se=+ # Disable searching hidden files and directories+ no-hidden+ # ignore files specified in .ignore and .gitignore in recursive searches+ ignore-files=.ignore+ ignore-files=.gitignore++Command line options are parsed in the following order: first the (default or+named) configuration file is loaded, then the remaining options and+arguments on the command line are parsed.++Option `--stats` displays the configuration file used after searching.++#### Named configuration files++Named configuration files are intended to streamline custom search tasks, by+reducing the number of command line options to just one `---FILE` to use the+collection of options specified in `FILE`.++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:++ ug ---FILE ...+ ugrep ---FILE ...++By constrast to the default `.ugrep` configuration file, an error is produced+when `FILE` is not found or cannot be loaded.++Named configuration files can be used to define a collection of options that+are specific to the requirements of a task in the development workflow of a+project. For example to report unresolved issues by checking the source code+and documentation for comments with FIXME and TODO items. Such named+configuration file can be localized to a project by placing it in the project+directory, or it can be made global by placing it in the home directory. For+visual feedback, a color scheme specific to this task can be specified with+option `colors` in the configuration `FILE` to help identify the output+produced by a named configuration as opposed to the default configuration.++#### Saving a configuration file++The `--save-config` option saves a `.ugrep` configuration file to the+working directory. The file contains a strict subset of options that are+deemed reasonably safe with respect to the search results reported.++The `--save-config=FILE` option saves the configuration to the specified `FILE`.+The configuration is written to standard output when `FILE` is a `-`.++🔝 [Back to table of contents](#toc)+ <a name="query"/> ### Interactive search with -Q@@ -2791,21 +2897,21 @@ and `https` sites: <a name="max"/> -### Limiting the number of matches with --depth, -m, --max-files, and --range+### Limiting the number of matches with -1,-2...-9, -K, -m, and --max-files --depth=[MIN,][MAX], -1, -2 ... -9, --10, --11 ... Restrict recursive searches from MIN to MAX directory levels deep, where -1 (--depth=1) searches the specified path without recursing into subdirectories. Note that -3 -5, -3-5, or -35 searches 3 to 5 levels deep. Enables -R if -R or -r is not specified.+ -K FIRST[,LAST], --range=FIRST[,LAST]+ Start searching at line FIRST, stop at line LAST when specified. -m NUM, --max-count=NUM Stop reading the input after NUM matches for each file processed. --max-files=NUM Restrict the number of files matched to NUM. Note that --sort or -J1 may be specified to produce replicable results. If --sort is specified, the number of threads spawned is limited to NUM.- --range=FIRST[,LAST]- Start searching at line FIRST, stop at line LAST when specified. --sort[=KEY] Displays matching files in the order specified by KEY in recursive searches. KEY can be `name' to sort by pathname (default), `best'@@ -2835,23 +2941,23 @@ the list of files sorted by pathname, using `--max-files=2`: ugrep --sort -R --max-files=2 -tc++ FIXME To search file `install.sh` for the occurrences of the word `make` after the-first line, we use `--range` with line number 2 to start searching,-where `-n` shows the line numbers in the output:+first line, we use `-K` with line number 2 to start searching, where `-n` shows+the line numbers in the output: - ugrep -n --range=2 -w make install.sh+ ugrep -n -K2 -w make install.sh Same, but restricting the search to lines 2 to 40 (inclusive): - ugrep -n --range=2,40 -w make install.sh+ ugrep -n -K2,40 -w make install.sh Same, but showing all lines 2 to 40 with `-y`: - ugrep -y -n --range=2,40 -w make install.sh+ ugrep -y -n -K2,40 -w make install.sh Same, but showing only the first four matching lines after line 2, with one line of context: - ugrep -n -C1 --range=2 -m4 -w make install.sh+ ugrep -n -C1 -K2 -m4 -w make install.sh 🔝 [Back to table of contents](#toc) @@ -3015,11 +3121,11 @@ in markdown: NAME- ugrep -- file pattern searcher+ ugrep, ug -- file pattern searcher SYNOPSIS- ugrep [OPTIONS] [-A NUM] [-B NUM] [-C[NUM]] [PATTERN] [-e PATTERN]- [-N PATTERN] [-f FILE] [-t TYPES] [-J [NUM]] [--sort[=KEY]]+ ugrep [OPTIONS] [-A NUM] [-B NUM] [-C[NUM]] [PATTERN] [-f FILE]+ [-e PATTERN] [-N PATTERN] [-t TYPES] [-J [NUM]] [--sort[=KEY]] [--color[=WHEN]|--colour[=WHEN]] [--pager[=COMMAND]] [FILE ...] DESCRIPTION@@ -3031,20 +3137,26 @@ in markdown: input line that matches at least one of the patterns is written to the standard output. - The ugrep utility accepts input of various encoding formats and normal-- izes the output to UTF-8. When a UTF byte order mark is present in the- input, the input is automatically normalized; otherwise, ugrep assumes- the input is ASCII, UTF-8, or raw binary. An input encoding format may- be specified with option --encoding.+ ugrep accepts input of various encoding formats and normalizes the out-+ put to UTF-8. When a UTF byte order mark is present in the input, the+ input is automatically normalized; otherwise, ugrep assumes the input+ is ASCII, UTF-8, or raw binary. An input encoding format may be speci-+ fied with option --encoding. If no FILE arguments are specified and standard input is read from a terminal, recursive searches are performed as if -R is specified. To force reading from standard input, specify `-' as a FILE argument. + Directories specified as FILE arguments are searched without recursing+ into subdirectories, unless -R, -r, or -2...-9 is specified.+ Hidden files and directories are ignored in recursive searches. Option- -. (--hidden) includes hidden files and directories in recursive+ -. (--hidden) includes hidden files and directories in recursive searches. + The ug command is equivalent to ugrep --config to load the default con-+ figuration file, which allows for customization, see CONFIGURATION.+ The following options are available: -A NUM, --after-context=NUM@@ -3118,9 +3230,14 @@ in markdown: (faint), `h' (highlight), `i' (invert), `u' (underline). Selec- tively overrides GREP_COLORS. - --no-confirm- Do not confirm actions in -Q query mode. The default is con-- firm.+ --config[=FILE], ---[FILE]+ Use configuration FILE. The default configuration is `.ugrep'.+ The working directory is checked first for FILE, then the home+ directory. The configuration FILE is parsed first, followed by+ the remaining command line options.++ --confirm+ Confirm actions in -Q query mode. The default is confirm. --cpp Output file matches in C++. See also options --format and -u. @@ -3286,8 +3403,8 @@ in markdown: Group matches per file. Adds a heading and a line break between results from different files. - --help, -?- Print a help message.+ --help [WHAT], -? [WHAT]+ Display a help message, specifically on WHAT when specified. --hexdump=[1-8][b][c][h] Output matches in 1 to 8 columns of 8 hexadecimal octets. The@@ -3299,7 +3416,8 @@ in markdown: --hidden, -. Search hidden files and directories. - -I Ignore matches in binary files. This option is equivalent to+ -I, --ignore-binary+ Ignore matches in binary files. This option is equivalent to the --binary-files=without-match option. -i, --ignore-case@@ -3310,54 +3428,55 @@ in markdown: Ignore files and directories matching the globs in each FILE that is encountered in recursive searches. The default FILE is `.gitignore'. Matching files and directories located in the- directory tree rooted at a FILE's location are ignored by tempo-- rarily overriding the --exclude and --exclude-dir globs. Files- and directories that are explicitly specified as command line- arguments are never ignored. This option may be repeated.+ directory of a FILE's location and in directories below are+ ignored by temporarily overriding the --exclude and+ --exclude-dir globs. Files and directories that are explicitly+ specified as command line arguments are never ignored. This+ option may be repeated. --include=GLOB- Search only files whose name matches GLOB using wildcard match-+ Search only files whose name matches GLOB using wildcard match- ing, same as -g GLOB. GLOB can use **, *, ?, and [...] as wild-- cards, and \ to quote a wildcard or backslash character liter-- ally. When GLOB contains a `/', full pathnames are matched.- Otherwise basenames are matched. When GLOB ends with a `/',+ cards, and \ to quote a wildcard or backslash character liter-+ ally. When GLOB contains a `/', full pathnames are matched.+ Otherwise basenames are matched. When GLOB ends with a `/', directories are included as if --include-dir is specified. Oth-- erwise files are included. Note that --exclude patterns take+ erwise files are included. Note that --exclude patterns take priority over --include patterns. GLOB should be quoted to pre- vent shell globbing. This option may be repeated. --include-dir=GLOB- Only directories whose name matches GLOB are included in recur-- sive searches. GLOB can use **, *, ?, and [...] as wildcards,- and \ to quote a wildcard or backslash character literally.+ Only directories whose name matches GLOB are included in recur-+ sive searches. GLOB can use **, *, ?, and [...] as wildcards,+ and \ to quote a wildcard or backslash character literally. When GLOB contains a `/', full pathnames are matched. Otherwise- basenames are matched. Note that --exclude-dir patterns take- priority over --include-dir patterns. GLOB should be quoted to+ basenames are matched. Note that --exclude-dir patterns take+ priority over --include-dir patterns. GLOB should be quoted to prevent shell globbing. This option may be repeated. --include-from=FILE- Read the globs from FILE and search only files and directories- whose name matches one or more globs (as if specified by- --include and --include-dir). Lines starting with a `#' and- empty lines in FILE are ignored. When FILE is a `-', standard+ Read the globs from FILE and search only files and directories+ whose name matches one or more globs (as if specified by+ --include and --include-dir). Lines starting with a `#' and+ empty lines in FILE are ignored. When FILE is a `-', standard input is read. This option may be repeated. --include-fs=MOUNTS- Only file systems specified by MOUNTS are included in recursive- searches. MOUNTS is a comma-separated list of mount points or- pathnames of directories on file systems. --include-fs=.- restricts recursive searches to the file system of the working- directory only. Note that --exclude-fs mounts take priority+ Only file systems specified by MOUNTS are included in recursive+ searches. MOUNTS is a comma-separated list of mount points or+ pathnames of directories on file systems. --include-fs=.+ restricts recursive searches to the file system of the working+ directory only. Note that --exclude-fs mounts take priority over --include-fs mounts. This option may be repeated. -J NUM, --jobs=NUM- Specifies the number of threads spawned to search files. By- default an optimum number of threads is spawned to search files- simultaneously. -J1 disables threading: files are searched in+ Specifies the number of threads spawned to search files. By+ default an optimum number of threads is spawned to search files+ simultaneously. -J1 disables threading: files are searched in the same order as specified. -j, --smart-case- Perform case insensitive matching unless a pattern contains an+ Perform case insensitive matching unless a pattern contains an upper case letter. This option applies to ASCII letters only. --json Output file matches in JSON. If -H, -n, -k, or -b is specified,@@ -3367,39 +3486,39 @@ in markdown: Start searching at line FIRST, stop at line LAST when specified. -k, --column-number- The column number of a matched pattern is displayed in front of- the respective matched line, starting at column 1. Tabs are+ The column number of a matched pattern is displayed in front of+ the respective matched line, starting at column 1. Tabs are expanded when columns are counted, see also option --tabs. -L, --files-without-match- Only the names of files not containing selected lines are writ-- ten to standard output. Pathnames are listed once per file+ Only the names of files not containing selected lines are writ-+ ten to standard output. Pathnames are listed once per file searched. If the standard input is searched, the string ``(standard input)'' is written. -l, --files-with-matches Only the names of files containing selected lines are written to- standard output. ugrep will only search a file until a match- has been found, making searches potentially less expensive.- Pathnames are listed once per file searched. If the standard+ standard output. ugrep will only search a file until a match+ has been found, making searches potentially less expensive.+ Pathnames are listed once per file searched. If the standard input is searched, the string ``(standard input)'' is written. --label=LABEL- Displays the LABEL value when input is read from standard input- where a file name would normally be printed in the output. The+ Displays the LABEL value when input is read from standard input+ where a file name would normally be printed in the output. The default value is `(standard input)'. --line-buffered Force output to be line buffered instead of block buffered. -M MAGIC, --file-magic=MAGIC- Only files matching the signature pattern MAGIC are searched.- The signature "magic bytes" at the start of a file are compared- to the MAGIC regex pattern. When matching, the file will be- searched. When MAGIC is preceded by a `!' or a `^', skip files+ Only files matching the signature pattern MAGIC are searched.+ The signature "magic bytes" at the start of a file are compared+ to the MAGIC regex pattern. When matching, the file will be+ searched. When MAGIC is preceded by a `!' or a `^', skip files with matching MAGIC signatures. This option may be repeated and- may be combined with options -O and -t to expand the search.- Every file on the search path is read, making searches poten-+ may be combined with options -O and -t to expand the search.+ Every file on the search path is read, making searches poten- tially more expensive. -m NUM, --max-count=NUM@@ -3409,89 +3528,88 @@ in markdown: Match all input. Same as specifying an empty pattern to search. --max-files=NUM- Restrict the number of files matched to NUM. Note that --sort- or -J1 may be specified to produce replicable results. If+ Restrict the number of files matched to NUM. Note that --sort+ or -J1 may be specified to produce replicable results. If --sort is specified, the number of threads spawned is limited to NUM. - --[no-]mmap[=MAX]- Do (not) use memory maps to search files. By default, memory- maps are used under certain conditions to improve performance.- When MAX is specified, use up to MAX mmap memory per thread.+ --mmap[=MAX]+ Use memory maps to search files. By default, memory maps are+ used under certain conditions to improve performance. When MAX+ is specified, use up to MAX mmap memory per thread. -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 when PATTERN does not match. Same as -e (?^PAT-- TERN). Negative PATTERN matches are removed before any other- specified patterns are matched. Note that longer patterns take- precedence over shorter patterns. This option may be repeated.+ 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 when PATTERN does not match. Same as -e (?^PAT-+ TERN). Negative PATTERN matches are removed before any other+ specified patterns are matched. Note that longer patterns take+ precedence over shorter patterns. This option may be repeated. -n, --line-number- Each output line is preceded by its relative line number in the- file, starting at line 1. The line number counter is reset for+ Each output line is preceded by its relative line number in the+ file, starting at line 1. The line number counter is reset for each file processed. --no-group-separator- Removes the group separator line from the output for context+ Removes the group separator line from the output for context options -A, -B, and -C. -O EXTENSIONS, --file-extension=EXTENSIONS- Search only files whose filename extensions match the specified- comma-separated list of EXTENSIONS, same as --include='*.ext'- for each `ext' in EXTENSIONS. When an `ext' is preceded by a- `!' or a `^', skip files whose filename extensions matches- `ext', same as --exclude='*.ext'. This option may be repeated- and may be combined with options -g, -M and -t to expand the+ Search only files whose filename extensions match the specified+ comma-separated list of EXTENSIONS, same as --include='*.ext'+ for each `ext' in EXTENSIONS. When an `ext' is preceded by a+ `!' or a `^', skip files whose filename extensions matches+ `ext', same as --exclude='*.ext'. This option may be repeated+ and may be combined with options -g, -M and -t to expand the recursive search. -o, --only-matching- Print only the matching part of lines. When multiple lines- match, the line numbers with option -n are displayed using `|'- as the field separator for each additional line matched by the- pattern. If -u is specified, ungroups multiple matches on the- same line. This option cannot be combined with options -A, -B,+ Print only the matching part of lines. When multiple lines+ match, the line numbers with option -n are displayed using `|'+ as the field separator for each additional line matched by the+ pattern. If -u is specified, ungroups multiple matches on the+ same line. This option cannot be combined with options -A, -B, -C, -v, and -y. --only-line-number The line number of the matching line in the file is output with-- out displaying the match. The line number counter is reset for+ out displaying the match. The line number counter is reset for each file processed. -P, --perl-regexp Interpret PATTERN as a Perl regular expression using PCRE2. -p, --no-dereference- If -R or -r is specified, no symbolic links are followed, even+ If -R or -r is specified, no symbolic links are followed, even when they are specified on the command line. --pager[=COMMAND]- When output is sent to the terminal, uses COMMAND to page- through the output. The default COMMAND is `less -R'. Enables+ When output is sent to the terminal, uses COMMAND to page+ through the output. The default COMMAND is `less -R'. Enables --heading and --line-buffered. --pretty- When output is sent to a terminal, enables --color, --heading,+ When output is sent to a terminal, enables --color, --heading, -T. -Q[DELAY], --query[=DELAY]- Query mode: user interface to perform interactive searches.- This mode requires an ANSI capable terminal. An optional DELAY- argument may be specified to reduce or increase the response+ Query mode: user interface to perform interactive searches.+ This mode requires an ANSI capable terminal. An optional DELAY+ argument may be specified to reduce or increase the response time to execute searches after the last key press, in increments- of 100ms, where the default is 5 (0.5s delay). No whitespace- may be given between -Q and its argument DELAY. Initial pat-- terns may be specified with -e PATTERN, i.e. a PATTERN argument+ of 100ms, where the default is 5 (0.5s delay). No whitespace+ may be given between -Q and its argument DELAY. Initial pat-+ terns may be specified with -e PATTERN, i.e. a PATTERN argument requires option -e. Press F1 or CTRL-Z to view the help screen.- Press F2 or CTRL-Y to invoke an editor to edit the file dis-- played on screen. The editor is taken from the environment- variable GREP_EDIT if defined, or EDITOR if GREP_EDIT is not+ Press F2 or CTRL-Y to invoke an editor to edit the file dis-+ played on screen. The editor is taken from the environment+ variable GREP_EDIT if defined, or EDITOR if GREP_EDIT is not defined. Enables --heading. -q, --quiet, --silent Quiet mode: suppress all output. ugrep will only search until a- match has been found, making searches potentially less expen-- sive.+ match has been found. -R, --dereference-recursive Recursively read all files under each directory. Follow all@@ -3505,17 +3623,18 @@ in markdown: bolic links only if they are on the command line. When -J1 is specified, files are searched in the same order as specified. - --range=FIRST[,LAST]- Start searching at line FIRST, stop at line LAST when specified.- -S, --dereference- If -r is specified, all symbolic links are followed, like -R.+ If -r is specified, all symbolic links are followed, like -R. The default is not to follow symbolic links. -s, --no-messages- Silent mode: nonexistent and unreadable files are ignored, i.e.+ Silent mode: nonexistent and unreadable files are ignored, i.e. their error messages are suppressed. + --save-config[=FILE]+ Save configuration FILE. By default `.ugrep' is saved. If FILE+ is a `-', write the configuration to standard output.+ --separator[=SEP] Use SEP as field separator between file name, line number, col- umn number, byte offset, and the matched line. The default is a@@ -3658,6 +3777,8 @@ in markdown: 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 ERE syntax. For an overview of the syntax see README.md or visit: @@ -3665,8 +3786,7 @@ in markdown: Note that `.' matches any non-newline character. Pattern `\n' matches a newline character. Multiple lines may be matched with patterns that- match newlines, unless one or more of the context options -A, -B, -C,- or -y is used, or option -v is used.+ match one or more newline characters. EXIT STATUS The ugrep utility exits with one of the following values:@@ -3677,9 +3797,37 @@ in markdown: >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 --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 loaded.++ The default configuration file is `.ugrep' when FILE is not specified.+ Default configuration files are optional; no error is produced when a+ default configuration file could not be found.++ The ug command is intended for context-dependent interactive searching+ and is equivalent to the ugrep --config command to load the default+ configuration file, when a default configuration file is present.++ 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.+ Empty lines and lines starting with a `#' are ignored.++ Command line options are parsed in the following order: first the con-+ figuration file is loaded, then the other command line options and+ arguments are parsed.++ The --save-config option saves a `.ugrep' configuration file to the+ working directory with a strict subset of options that are deemed safe.+ 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 to match pathnames and@@ -3692,9 +3840,11 @@ in markdown: 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 `!' as specified with -g!GLOB, or specified- in a FILE with --include-from=FILE or --exclude-from=FILE, its match is- negated.+ 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+ ignored. Glob Syntax and Conventions @@ -3750,10 +3900,6 @@ in markdown: a\?b Matches a?b, but not a, b, ab, axb, a/b - Lines in the --exclude-from and --include-from files are ignored when- empty or start with a `#'. When a glob is prefixed with `!', negates- the match.- ENVIRONMENT GREP_PATH May be used to specify a file path to pattern files. The file@@ -3762,7 +3908,7 @@ in markdown: GREP_EDITOR May be used to specify an editor command to invoke with CTRL-Y- within the query UI opened with option -Q. When undefined, the+ while using the query UI with option -Q. When undefined, the command defined by EDITOR is invoked. GREP_COLOR@@ -3776,8 +3922,8 @@ in markdown: 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 have priority over- GREP_COLOR. Option --colors has priority over GREP_COLORS.+ 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@@ -3940,9 +4086,9 @@ in markdown: 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. When field %u is found anywhere in the specified- format string, matching lines are output only once unless option -u,- --ungroup is used or when a newline is matched.+ on the same line. If field %u is specified anywhere in a format+ string, then matching lines are output only once unless option -u,+ --ungroup is specified or when one or more newlines are matched. Additional formatting options: @@ -3959,7 +4105,7 @@ in markdown: the FORMAT when ending the search. The context options -A, -B, -C, -y, and options -v, --break, --heading,- --color, -T, and --null have no effect on the formatted output.+ --color, -T, and --null have no effect on formatted output. EXAMPLES Display lines containing the word `patricia' in `myfile.txt':@@ -4091,7 +4237,7 @@ in markdown: - ugrep 2.3.2 June 29, 2020 UGREP(1)+ ugrep 2.4.0 July 09, 2020 UGREP(1) 🔝 [Back to table of contents](#toc)
@@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles.-# Generated by GNU Autoconf 2.69 for ugrep 1.8.+# Generated by GNU Autoconf 2.69 for ugrep 2.4. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.@@ -579,8 +579,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='ugrep' PACKAGE_TARNAME='ugrep'-PACKAGE_VERSION='1.8'-PACKAGE_STRING='ugrep 1.8'+PACKAGE_VERSION='2.4'+PACKAGE_STRING='ugrep 2.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -640,6 +640,7 @@ build_os build_vendor build_cpu build+LN_S RANLIB am__fastdepCC_FALSE am__fastdepCC_TRUE@@ -1309,7 +1310,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 1.8 to adapt to many kinds of systems.+\`configure' configures ugrep 2.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1379,7 +1380,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in- short | recursive ) echo "Configuration of ugrep 1.8:";;+ short | recursive ) echo "Configuration of ugrep 2.4:";; esac cat <<\_ACEOF @@ -1513,7 +1514,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF-ugrep configure 1.8+ugrep configure 2.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc.@@ -2230,7 +2231,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 1.8, which was+It was created by ugrep $as_me 2.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@@@ -3096,7 +3097,7 @@ fi # Define the identity of the package. PACKAGE='ugrep'- VERSION='1.8'+ VERSION='2.4' cat >>confdefs.h <<_ACEOF@@ -6555,6 +6556,17 @@ else fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5+$as_echo_n "checking whether ln -s works... " >&6; }+LN_S=$as_ln_s+if test "$LN_S" = "ln -s"; then+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5+$as_echo "yes" >&6; }+else+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5+$as_echo "no, using $LN_S" >&6; }+fi+ # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||@@ -7648,7 +7660,7 @@ $as_echo_n "checking whether ${CXX} supports AVX intrinsics... " >&6; } int main () {-__m512 n = _mm512_set1_epi8(42); unsigned long long m = _mm512_cmpeq_epi8_mask(n, n);+__m512 n = _mm512_set1_epi8(42); (void)_mm512_cmpeq_epi8_mask(n, n); ; return 0; }@@ -7660,7 +7672,7 @@ else fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "x$mavx_ok" = "xyes"; then- SIMD_FLAGS="-march=native -mavx512bw -DHAVE_AVX512BW"+ SIMD_FLAGS="-mavx512bw -DHAVE_AVX512BW" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */@@ -7668,7 +7680,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext int main () {-__m256i n = _mm256_set1_epi8(42); n =_mm256_and_si256(n, n);+__m256i n = _mm256_set1_epi8(42); (void)_mm256_movemask_epi8(_mm256_and_si256(n, n)); ; return 0; }@@ -7680,7 +7692,7 @@ else fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "x$mavx_ok" = "xyes"; then- SIMD_FLAGS="-march=native -mavx -DHAVE_AVX"+ SIMD_FLAGS="-mavx2 -DHAVE_AVX2" fi fi CXXFLAGS=$save_CXXFLAGS@@ -7708,7 +7720,7 @@ $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CXX} supports SSE2 intrinsics" >&5 $as_echo_n "checking whether ${CXX} supports SSE2 intrinsics... " >&6; } save_CXXFLAGS=$CXXFLAGS- CXXFLAGS="-msse2"+ CXXFLAGS="-march=native" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <emmintrin.h>@@ -8374,7 +8386,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 1.8, which was+This file was extended by ugrep $as_me 2.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES@@ -8440,7 +8452,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\-ugrep config.status 1.8+ugrep config.status 2.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\"
@@ -1,4 +1,4 @@-AC_INIT(ugrep,1.8)+AC_INIT(ugrep,2.4) AM_INIT_AUTOMAKE([foreign]) AM_CONFIG_HEADER(config.h) AC_COPYRIGHT([Copyright (C) 2019-2020 Robert van Engelen, Genivia Inc.])@@ -31,6 +31,7 @@ AC_PROG_CXX AM_PROG_AR AC_PROG_RANLIB AC_PROG_INSTALL+AC_PROG_LN_S AC_CANONICAL_HOST @@ -159,17 +160,17 @@ if test "x$with_no_avx" = "xno"; then AC_MSG_CHECKING([whether ${CXX} supports AVX intrinsics]) save_CXXFLAGS=$CXXFLAGS CXXFLAGS="-march=native"- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <immintrin.h>]], [[__m512 n = _mm512_set1_epi8(42); unsigned long long m = _mm512_cmpeq_epi8_mask(n, n);]])],+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <immintrin.h>]], [[__m512 n = _mm512_set1_epi8(42); (void)_mm512_cmpeq_epi8_mask(n, n);]])], [mavx_ok=yes], [mavx_ok=no]) if test "x$mavx_ok" = "xyes"; then- SIMD_FLAGS="-march=native -mavx512bw -DHAVE_AVX512BW"+ SIMD_FLAGS="-mavx512bw -DHAVE_AVX512BW" else- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <immintrin.h>]], [[__m256i n = _mm256_set1_epi8(42); n =_mm256_and_si256(n, n);]])],+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <immintrin.h>]], [[__m256i n = _mm256_set1_epi8(42); (void)_mm256_movemask_epi8(_mm256_and_si256(n, n));]])], [mavx_ok=yes], [mavx_ok=no]) if test "x$mavx_ok" = "xyes"; then- SIMD_FLAGS="-march=native -mavx -DHAVE_AVX"+ SIMD_FLAGS="-mavx2 -DHAVE_AVX2" fi fi CXXFLAGS=$save_CXXFLAGS@@ -190,7 +191,7 @@ if test "x$with_no_sse2" = "xno"; then AC_MSG_RESULT(no) AC_MSG_CHECKING([whether ${CXX} supports SSE2 intrinsics]) save_CXXFLAGS=$CXXFLAGS- CXXFLAGS="-msse2"+ CXXFLAGS="-march=native" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <emmintrin.h>]], [[__m128i n = _mm_set1_epi8(42);]])], [msse2_ok=yes], [msse2_ok=no])
@@ -41,11 +41,12 @@ #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(__BORLANDC__) namespace reflex {+typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; }-#else+#elif !defined(CONFIG_H) # include <stdint.h> #endif
@@ -154,7 +154,7 @@ class BoostMatcher : public PatternMatcher<boost::regex> { if (n == 0) return std::pair<const char*,size_t>(txt_, len_); if (itr_ == fin_ || n >= (*itr_).size() || !(*itr_)[n].matched)- return std::pair<const char*,size_t>(NULL, 0);+ return std::pair<const char*,size_t>(static_cast<const char*>(NULL), 0); // cast to appease MSVC 2010 return std::pair<const char*,size_t>((*itr_)[n].first, (*itr_)[n].second - (*itr_)[n].first); } /// Returns the group capture identifier containing the group capture index >0 and name (or NULL) of a named group capture, or (1,NULL) by default@@ -163,9 +163,9 @@ class BoostMatcher : public PatternMatcher<boost::regex> { { grp_ = 1; if (itr_ == fin_ || (*itr_).size() <= 1)- return std::pair<size_t,const char*>(0, NULL);+ return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 if ((*itr_)[1].matched)- return std::pair<size_t,const char*>(1, NULL);+ return std::pair<size_t,const char*>(1, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 return group_next_id(); } /// Returns the next group capture identifier containing the group capture index >0 and name (or NULL) of a named group capture, or (0,NULL) when no more groups matched@@ -173,14 +173,14 @@ class BoostMatcher : public PatternMatcher<boost::regex> { /// @returns a pair of size_t and string { if (itr_ == fin_)- return std::pair<size_t,const char*>(0, NULL); + return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 size_t n = (*itr_).size(); while (++grp_ < n) if ((*itr_)[grp_].matched) break; if (grp_ < n)- return std::pair<size_t,const char*>(grp_, NULL);- return std::pair<size_t,const char*>(1, NULL);+ return std::pair<size_t,const char*>(grp_, static_cast<const char*>(NULL)); // cast to appease MSVC 2010+ return std::pair<size_t,const char*>(1, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 } protected: /// The match method Const::SCAN, Const::FIND, Const::SPLIT, or Const::MATCH, implemented with boost::regex.
@@ -156,8 +156,6 @@ extern "C" void REFLEX_DBGOUT_(const char *log, const char *file, int line); #ifdef DEBUG -#include <stdio.h>- #define DBGCHK(c) assert(c) #define DBGLOG _DBGLOG
@@ -38,7 +38,7 @@ #define REFLEX_INPUT_H #include <reflex/utf8.h>-#include <stdio.h>+#include <cstdio> #include <cstring> #include <iostream> #include <string>
@@ -139,19 +139,19 @@ class Matcher : public PatternMatcher<reflex::Pattern> { { if (n == 0) return std::pair<const char*,size_t>(txt_, len_);- return std::pair<const char*,size_t>(NULL, 0);+ return std::pair<const char*,size_t>(static_cast<const char*>(NULL), 0); // cast to appease MSVC 2010 } /// Returns the group capture identifier containing the group capture index >0 and name (or NULL) of a named group capture, or (1,NULL) by default virtual std::pair<size_t,const char*> group_id() /// @returns a pair of size_t and string {- return std::pair<size_t,const char*>(accept(), NULL);+ return std::pair<size_t,const char*>(accept(), static_cast<const char*>(NULL)); // cast to appease MSVC 2010 } /// Returns the next group capture identifier containing the group capture index >0 and name (or NULL) of a named group capture, or (0,NULL) when no more groups matched virtual std::pair<size_t,const char*> group_next_id() /// @returns (0,NULL) {- return std::pair<size_t,const char*>(0, NULL);+ return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 } /// Returns the position of the last indent stop. size_t last_stop()@@ -381,10 +381,10 @@ class Matcher : public PatternMatcher<reflex::Pattern> { { return HW & (1ULL << 62); }- /// Check CPU hardware for AVX capability.- static bool have_HW_AVX()+ /// Check CPU hardware for AVX2 capability.+ static bool have_HW_AVX2() {- return HW & (1ULL << 28);+ return HW & (1ULL << 37); } /// Check CPU hardware for SSE2 capability. static bool have_HW_SSE2()@@ -889,7 +889,7 @@ unrolled: // skip one char to keep searching set_current(++cur_); // allow FIND with "N" to match an empty line, with ^$ etc.- if (cap_ == 0 || !opt_.N || (!bol && (c1 == '\n' || (c1 == '\r' && peek() == '\n'))))+ if (cap_ == 0 || !opt_.N) goto scan; DBGLOG("Accept empty match"); }
@@ -219,11 +219,11 @@ class PCRE2Matcher : public PatternMatcher<std::string> { if (n == 0) return std::pair<const char*,size_t>(txt_, len_); if (dat_ == NULL || n >= pcre2_get_ovector_count(dat_))- return std::pair<const char*,size_t>(NULL, 0);+ return std::pair<const char*,size_t>(static_cast<const char*>(NULL), 0); // cast to appease MSVC 2010 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(dat_); size_t n2 = 2 * n; if (ovector[n2] == PCRE2_UNSET)- return std::pair<const char*,size_t>(NULL, 0);+ return std::pair<const char*,size_t>(static_cast<const char*>(NULL), 0); // cast to appease MSVC 2010 return std::pair<const char*,size_t>(buf_ + ovector[n2], ovector[n2 + 1] - ovector[n2]); } /// Returns the group capture identifier containing the group capture index >0 and name (or NULL) of a named group capture, or (1,NULL) by default@@ -232,7 +232,7 @@ class PCRE2Matcher : public PatternMatcher<std::string> { { grp_ = 1; if (dat_ == NULL || pcre2_get_ovector_count(dat_) <= 1)- return std::pair<size_t,const char*>(0, NULL);+ return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(dat_); if (ovector[2] == PCRE2_UNSET) return group_next_id();@@ -243,14 +243,14 @@ class PCRE2Matcher : public PatternMatcher<std::string> { /// @returns a pair of size_t and string { if (dat_ == NULL)- return std::pair<size_t,const char*>(0, NULL);+ return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 PCRE2_SIZE n = pcre2_get_ovector_count(dat_); PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(dat_); while (++grp_ < n) if (ovector[2 * grp_] != PCRE2_UNSET) break; if (grp_ >= n)- return std::pair<size_t,const char*>(0, NULL);+ return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 return id(); } protected:@@ -273,7 +273,7 @@ class PCRE2Matcher : public PatternMatcher<std::string> { return std::pair<size_t,const char*>(grp_, reinterpret_cast<const char*>(p + 2)); } }- return std::pair<size_t,const char*>(grp_, NULL);+ return std::pair<size_t,const char*>(grp_, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 } /// Compile pattern for jit partial matching and allocate match data. void compile()
@@ -153,7 +153,7 @@ class StdMatcher : public PatternMatcher<std::regex> { if (n == 0) return std::pair<const char*,size_t>(txt_, len_); if (itr_ == fin_ || n >= (*itr_).size() || !(*itr_)[n].matched)- return std::pair<const char*,size_t>(NULL, 0);+ return std::pair<const char*,size_t>(static_cast<const char*>(NULL), 0); // cast to appease MSVC 2010 return std::pair<const char*,size_t>((*itr_)[n].first, (*itr_)[n].second - (*itr_)[n].first); } /// Returns the group capture identifier containing the group capture index >0 and name (or NULL) of a named group capture, or (1,NULL) by default@@ -162,9 +162,9 @@ class StdMatcher : public PatternMatcher<std::regex> { { grp_ = 1; if (itr_ == fin_ || (*itr_).size() <= 1)- return std::pair<size_t,const char*>(0, NULL);+ return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 if ((*itr_)[1].matched)- return std::pair<size_t,const char*>(1, NULL);+ return std::pair<size_t,const char*>(1, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 return group_next_id(); } /// Returns the next group capture identifier containing the group capture index >0 and name (or NULL) of a named group capture, or (0,NULL) when no more groups matched@@ -172,14 +172,14 @@ class StdMatcher : public PatternMatcher<std::regex> { /// @returns a pair of size_t and string { if (itr_ == fin_)- return std::pair<size_t,const char*>(0, NULL); + return std::pair<size_t,const char*>(0, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 size_t n = (*itr_).size(); while (++grp_ < n) if ((*itr_)[grp_].matched) break; if (grp_ < n)- return std::pair<size_t,const char*>(grp_, NULL);- return std::pair<size_t,const char*>(1, NULL);+ return std::pair<size_t,const char*>(grp_, static_cast<const char*>(NULL)); // cast to appease MSVC 2010+ return std::pair<size_t,const char*>(1, static_cast<const char*>(NULL)); // cast to appease MSVC 2010 } protected: /// The match method Const::SCAN, Const::FIND, Const::SPLIT, or Const::MATCH, implemented with std::regex.
@@ -244,6 +244,7 @@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@+LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@
@@ -38,7 +38,7 @@ #if defined(HAVE_AVX512BW) # include <immintrin.h>-#elif defined(HAVE_AVX)+#elif defined(HAVE_AVX2) # include <immintrin.h> #elif defined(HAVE_SSE2) # include <emmintrin.h>@@ -46,19 +46,19 @@ # include <arm_neon.h> #endif -#if defined(HAVE_AVX512BW) || defined(HAVE_AVX) || defined(HAVE_SSE2)+#if defined(HAVE_AVX512BW) || defined(HAVE_AVX2) || defined(HAVE_SSE2) # ifdef _MSC_VER # include <intrin.h>-# define cpuid __cpuid+# define cpuidex __cpuidex # else # include <cpuid.h>-# define cpuid(CPUInfo, InfoType) __cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3])+# define cpuidex(CPUInfo, id, subid) __cpuid_count(id, subid, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]) # endif #endif namespace reflex { -#if defined(HAVE_AVX512BW) || defined(HAVE_AVX) || defined(HAVE_SSE2)+#if defined(HAVE_AVX512BW) || defined(HAVE_AVX2) || defined(HAVE_SSE2) #ifdef _MSC_VER #pragma intrinsic(_BitScanForward)@@ -90,16 +90,16 @@ inline uint32_t ctzl(uint64_t x) uint64_t Matcher::get_HW() {- int CPUInfo1[4] = { -1, 0, 0, 0 };- int CPUInfo7[4] = { 0, 0, 0, 0 };- cpuid(CPUInfo1, 0);+ int CPUInfo1[4] = { 0, 0, 0, 0 };+ int CPUInfo7[4] = { 0, 0, 0, 0 };+ cpuidex(CPUInfo1, 0, 0); int n = CPUInfo1[0];- if (n < 1)+ if (n <= 0) return 0ULL;- cpuid(CPUInfo1, 1);+ cpuidex(CPUInfo1, 1, 0); // cpuid EAX=1 if (n >= 7)- cpuid(CPUInfo7, 7);- return static_cast<uint64_t>(CPUInfo1[2]) | (static_cast<uint64_t>(CPUInfo7[1]) << 32);+ cpuidex(CPUInfo7, 7, 0); // cpuid EAX=7, ECX=0+ return static_cast<uint32_t>(CPUInfo1[2]) | (static_cast<uint64_t>(static_cast<uint32_t>(CPUInfo7[1])) << 32); } #else@@ -152,7 +152,7 @@ void Matcher::boyer_moore_init(const char *pat, size_t len) score += bms_[static_cast<uint8_t>(pat[i])]; score /= n; uint8_t fch = freq[static_cast<uint8_t>(pat[lcp_])];- if (!have_HW_SSE2() && !have_HW_AVX() && !have_HW_AVX512BW())+ if (!have_HW_SSE2() && !have_HW_AVX2() && !have_HW_AVX512BW()) { // if scoring is high and freq is high, then use improved Boyer-Moore instead of memchr() #if defined(__SSE2__) || defined(__x86_64__) || _M_IX86_FP == 2@@ -383,7 +383,7 @@ bool Matcher::advance() #if defined(HAVE_AVX512BW) && (!defined(_MSC_VER) || defined(_WIN64)) if (have_HW_AVX512BW()) {- // implements SIMD string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html+ // implements AVX512 string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html __m512i vlcp = _mm512_set1_epi8(pre[lcp_]); __m512i vlcs = _mm512_set1_epi8(pre[lcs_]); while (s + 64 < e)@@ -416,9 +416,9 @@ bool Matcher::advance() s += 64; } }- else if (have_HW_AVX())+ else if (have_HW_AVX2()) {- // implements SIMD string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html+ // implements AVX2 string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html __m256i vlcp = _mm256_set1_epi8(pre[lcp_]); __m256i vlcs = _mm256_set1_epi8(pre[lcs_]); while (s + 32 < e)@@ -455,7 +455,7 @@ bool Matcher::advance() } else if (have_HW_SSE2()) {- // implements SIMD string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html+ // implements SSE2 string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html __m128i vlcp = _mm_set1_epi8(pre[lcp_]); __m128i vlcs = _mm_set1_epi8(pre[lcs_]); while (s + 16 < e)@@ -490,10 +490,10 @@ bool Matcher::advance() s += 16; } }-#elif defined(HAVE_AVX)- if (have_HW_AVX())+#elif defined(HAVE_AVX2)+ if (have_HW_AVX2()) {- // implements SIMD string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html+ // implements AVX2 string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html __m256i vlcp = _mm256_set1_epi8(pre[lcp_]); __m256i vlcs = _mm256_set1_epi8(pre[lcs_]); while (s + 32 < e)@@ -530,7 +530,7 @@ bool Matcher::advance() } else if (have_HW_SSE2()) {- // implements SIMD string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html+ // implements SSE2 string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html __m128i vlcp = _mm_set1_epi8(pre[lcp_]); __m128i vlcs = _mm_set1_epi8(pre[lcs_]); while (s + 16 < e)@@ -568,7 +568,7 @@ bool Matcher::advance() #elif defined(HAVE_SSE2) if (have_HW_SSE2()) {- // implements SIMD string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html+ // implements SSE2 string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html __m128i vlcp = _mm_set1_epi8(pre[lcp_]); __m128i vlcs = _mm_set1_epi8(pre[lcs_]); while (s + 16 < e)@@ -604,7 +604,7 @@ bool Matcher::advance() } } #elif defined(HAVE_NEON)- // implements SIMD string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html+ // implements NEON/AArch64 string search scheme based on in http://0x80.pl/articles/simd-friendly-karp-rabin.html but 64 bit optimized uint8x16_t vlcp = vdupq_n_u8(pre[lcp_]); uint8x16_t vlcs = vdupq_n_u8(pre[lcs_]); while (s + 16 < e)
@@ -1712,12 +1712,12 @@ void Pattern::compile_transition( case '.': if (is_modified('s', modifiers, loc)) {- static const uint64_t dot[5] = { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0 };+ static const uint64_t dot[5] = { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0 }; chars |= Chars(dot); } else {- static const uint64_t dot[5] = { 0xFFFFFFFFFFFFFBFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0 };+ static const uint64_t dot[5] = { 0xFFFFFFFFFFFFFBFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0 }; chars |= Chars(dot); } break;@@ -1946,20 +1946,20 @@ void Pattern::posix(size_t index, Chars& chars) const { DBGLOG("posix(%lu)", index); static const uint64_t posix_chars[14][5] = {- { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0, 0, 0 }, // ASCII- { 0x0000000100003E00, 0x0000000000000000, 0, 0, 0 }, // Space: \t-\r, ' '- { 0x03FF000000000000, 0x0000007E0000007E, 0, 0, 0 }, // XDigit: 0-9, A-F, a-f- { 0x00000000FFFFFFFF, 0x8000000000000000, 0, 0, 0 }, // Cntrl: \x00-0x1F, \0x7F- { 0xFFFFFFFF00000000, 0x7FFFFFFFFFFFFFFF, 0, 0, 0 }, // Print: ' '-'~'- { 0x03FF000000000000, 0x07FFFFFE07FFFFFE, 0, 0, 0 }, // Alnum: 0-9, A-Z, a-z- { 0x0000000000000000, 0x07FFFFFE07FFFFFE, 0, 0, 0 }, // Alpha: A-Z, a-z- { 0x0000000100000200, 0x0000000000000000, 0, 0, 0 }, // Blank: \t, ' '- { 0x03FF000000000000, 0x0000000000000000, 0, 0, 0 }, // Digit: 0-9- { 0xFFFFFFFE00000000, 0x7FFFFFFFFFFFFFFF, 0, 0, 0 }, // Graph: '!'-'~'- { 0x0000000000000000, 0x07FFFFFE00000000, 0, 0, 0 }, // Lower: a-z- { 0xFC00FFFE00000000, 0x78000001F8000001, 0, 0, 0 }, // Punct: '!'-'/', ':'-'@', '['-'`', '{'-'~'- { 0x0000000000000000, 0x0000000007FFFFFE, 0, 0, 0 }, // Upper: A-Z- { 0x03FF000000000000, 0x07FFFFFE87FFFFFE, 0, 0, 0 }, // Word: 0-9, A-Z, a-z, _+ { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL, 0ULL, 0ULL, 0ULL }, // ASCII+ { 0x0000000100003E00ULL, 0x0000000000000000ULL, 0ULL, 0ULL, 0ULL }, // Space: \t-\r, ' '+ { 0x03FF000000000000ULL, 0x0000007E0000007EULL, 0ULL, 0ULL, 0ULL }, // XDigit: 0-9, A-F, a-f+ { 0x00000000FFFFFFFFULL, 0x8000000000000000ULL, 0ULL, 0ULL, 0ULL }, // Cntrl: \x00-0x1F, \0x7F+ { 0xFFFFFFFF00000000ULL, 0x7FFFFFFFFFFFFFFFULL, 0ULL, 0ULL, 0ULL }, // Print: ' '-'~'+ { 0x03FF000000000000ULL, 0x07FFFFFE07FFFFFEULL, 0ULL, 0ULL, 0ULL }, // Alnum: 0-9, A-Z, a-z+ { 0x0000000000000000ULL, 0x07FFFFFE07FFFFFEULL, 0ULL, 0ULL, 0ULL }, // Alpha: A-Z, a-z+ { 0x0000000100000200ULL, 0x0000000000000000ULL, 0ULL, 0ULL, 0ULL }, // Blank: \t, ' '+ { 0x03FF000000000000ULL, 0x0000000000000000ULL, 0ULL, 0ULL, 0ULL }, // Digit: 0-9+ { 0xFFFFFFFE00000000ULL, 0x7FFFFFFFFFFFFFFFULL, 0ULL, 0ULL, 0ULL }, // Graph: '!'-'~'+ { 0x0000000000000000ULL, 0x07FFFFFE00000000ULL, 0ULL, 0ULL, 0ULL }, // Lower: a-z+ { 0xFC00FFFE00000000ULL, 0x78000001F8000001ULL, 0ULL, 0ULL, 0ULL }, // Punct: '!'-'/', ':'-'@', '['-'`', '{'-'~'+ { 0x0000000000000000ULL, 0x0000000007FFFFFEULL, 0ULL, 0ULL, 0ULL }, // Upper: A-Z+ { 0x03FF000000000000ULL, 0x07FFFFFE87FFFFFEULL, 0ULL, 0ULL, 0ULL }, // Word: 0-9, A-Z, a-z, _ }; chars |= Chars(posix_chars[index]); }@@ -2065,7 +2065,7 @@ void Pattern::encode_dfa(DFA::State *start) // add final dead state (HALT opcode) only when needed, i.e. skip dead state if all chars 0-255 are already covered if (hi <= 0xFF) {- state->edges[hi] = std::pair<Char,DFA::State*>(0xFF, NULL);+ state->edges[hi] = std::pair<Char,DFA::State*>(0xFF, static_cast<DFA::State*>(NULL)); // cast to appease MSVC 2010 ++nop_; } #else@@ -2088,7 +2088,7 @@ void Pattern::encode_dfa(DFA::State *start) // add final dead state (HALT opcode) only when needed, i.e. skip dead state if all chars 0-255 are already covered if (!covered) {- state->edges[lo] = std::pair<Char,DFA::State*>(0x00, NULL);+ state->edges[lo] = std::pair<Char,DFA::State*>(0x00, static_cast<DFA::State*>(NULL)); // cast to appease MSVC 2010 ++nop_; } #endif
@@ -15,11 +15,11 @@ mkdir -p man echo '.TH UGREP "1" "'`date '+%B %d, %Y'`'" "ugrep '$1'" "User Commands"' > man/ugrep.1 cat >> man/ugrep.1 << 'END' .SH NAME-\fBugrep\fR -- file pattern searcher+\fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS .B ugrep-[\fIOPTIONS\fR] [\fB-A\fR \fINUM\fR] [\fB-B\fR \fINUM\fR] [\fB-C\fR[\fINUM\fR]] [\fIPATTERN\fR] [\fB-e\fR \fIPATTERN\fR]- [\fB-N\fR \fIPATTERN\fR] [\fB-f\fR \fIFILE\fR] [\fB-t\fR \fITYPES\fR] [\fB-J\fR [\fINUM\fR]] [\fB--sort\fR[=\fIKEY\fR]]+[\fIOPTIONS\fR] [\fB-A\fR \fINUM\fR] [\fB-B\fR \fINUM\fR] [\fB-C\fR[\fINUM\fR]] [\fIPATTERN\fR] [\fB-f\fR \fIFILE\fR]+ [\fB-e\fR \fIPATTERN\fR] [\fB-N\fR \fIPATTERN\fR] [\fB-t\fR \fITYPES\fR] [\fB-J\fR [\fINUM\fR]] [\fB--sort\fR[=\fIKEY\fR]] [\fB--color\fR[=\fIWHEN\fR]|\fB--colour\fR[=\fIWHEN\fR]] [\fB--pager\fR[=\fICOMMAND\fR]] [\fIFILE\fR \fI...\fR] .SH DESCRIPTION The \fBugrep\fR utility searches any given input files, selecting lines that@@ -29,20 +29,27 @@ input lines if the RE in the pattern matches one or more newlines in the input. An empty pattern matches every line. Each input line that matches at least one of the patterns is written to the standard output. .PP-The \fBugrep\fR utility accepts input of various encoding formats and-normalizes the output to UTF-8. When a UTF byte order mark is present in the-input, the input is automatically normalized; otherwise, \fBugrep\fR assumes-the input is ASCII, UTF-8, or raw binary. An input encoding format may be-specified with option \fB--encoding\fR.+\fBugrep\fR accepts input of various encoding formats and normalizes the output+to UTF-8. When a UTF byte order mark is present in the input, the input is+automatically normalized; otherwise, \fBugrep\fR assumes the input is ASCII,+UTF-8, or raw binary. An input encoding format may be specified with option+\fB--encoding\fR. .PP If no \fIFILE\fR arguments are specified and standard input is read from a terminal, recursive searches are performed as if \fB-R\fR is specified. To force reading from standard input, specify `-' as a \fIFILE\fR argument. .PP+Directories specified as \fIFILE\fR arguments are searched without recursing+into subdirectories, unless \fB-R\fR, \fB-r\fR, or \fB-2\fR...\fB-9\fR is+specified.+.PP Hidden files and directories are ignored in recursive searches. Option \fB-.\fR (\fB--hidden\fR) includes hidden files and directories in recursive searches. .PP+The \fBug\fR command is equivalent to \fBugrep --config\fR to load the default+configuration file, which allows for customization, see CONFIGURATION.+.PP The following options are available: END src/ugrep --help \@@ -50,6 +57,7 @@ src/ugrep --help \ | sed -e 's/\([^\\]\)\\/\1\\\\/g' \ | sed \ -e '/^$/ d' \+ -e '/^ Long options may start/ d' \ -e '/^ The ugrep/ d' \ -e '/^ 0 / d' \ -e '/^ 1 / d' \@@ -75,6 +83,8 @@ cat >> man/ugrep.1 << 'END' A `--' signals the end of options; the rest of the parameters are \fIFILE\fR arguments, allowing filenames to begin with a `-' character. .PP+Long options may start with `\FB--no-\fR' to disable, when applicable.+.PP 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: .IP@@ -82,8 +92,7 @@ https://github.com/Genivia/ugrep .PP Note that `.' matches any non-newline character. Pattern `\\n' matches a newline character. Multiple lines may be matched with patterns that match-newlines, unless one or more of the context options \fB-A\fR, \fB-B\fR,-\fB-C\fR, or \fB-y\fR is used, or option \fB-v\fR is used.+one or more newline characters. .SH "EXIT STATUS" The \fBugrep\fR utility exits with one of the following values: .IP 0@@ -95,6 +104,30 @@ An error occurred. .PP If \fB-q\fR or \fB--quiet\fR or \fB--silent\fR is used and a line is selected, the exit status is 0 even if an error occurred.+.SH CONFIGURATION+The \fBug\fR command is intended for context-dependent interactive searching+and is equivalent to the \fBugrep --config\fR command to load the default+configuration file `.ugrep' when present in the working directory or in the+home directory.+.PP+A configuration file contains `NAME=VALUE' pairs per line, where `NAME` is the+name of a long option (without `--') and `=VALUE' is an argument, which is+optional and may be omitted depending on the option. Empty lines and lines+starting with a `#' are ignored.+.PP+The \fB--config\fR=\fIFILE\fR option and its abbreviated form+\fB---\fR\fIFILE\fR load the specified configuration file located in the+working directory or, when not found, located in the home directory. An error+is produced when \fIFILE\fR is not found or cannot be read.+.PP+Command line options are parsed in the following order: the configuration file+is loaded first, followed by the remaining options and arguments on the command+line.+.PP+The \fB--save-config\fR option saves a `.ugrep' configuration file to the+working directory with a subset of the current options. The+\fB--save-config\fR=\fIFILE\fR option saves the configuration to \fIFILE\fR.+The configuration is written to standard output when \fIFILE\fR is a `-'. .SH GLOBBING Globbing is used by options \fB-g\fR, \fB--include\fR, \fB--include-dir\fR, \fB--include-from\fR, \fB--exclude\fR, \fB--exclude-dir\fR,@@ -103,14 +136,16 @@ Globbing supports gitignore syntax and the corresponding matching rules. When a glob ends in a path separator it matches directories as if \fB--include-dir\fR or \fB--exclude-dir\fR is specified. When a glob contains a path separator `/', the full pathname is matched. Otherwise the basename of-a file or directory is matched. For example, \fB*.h\fR matches \fIfoo.h\fR and-\fIbar/foo.h\fR. \fBbar/*.h\fR matches \fIbar/foo.h\fR but not \fIfoo.h\fR and-not \fIbar/bar/foo.h\fR. Use a leading `/' to force \fB/*.h\fR to match-\fIfoo.h\fR but not \fIbar/foo.h\fR.+a file or directory is matched. For example, \fB*.h\fR matches foo.h and+bar/foo.h. \fBbar/*.h\fR matches bar/foo.h but not foo.h and not+bar/bar/foo.h. Use a leading `/' to force \fB/*.h\fR to match foo.h but not+bar/foo.h. .PP-When a glob starts with a `!' as specified with \fB-g\fR!\fIGLOB\fR, or-specified in a \fIFILE\fR with \fB--include-from\fR=\fIFILE\fR or-\fB--exclude-from\fR=\fIFILE\fR, its match is negated.+When a glob starts with a `^' or a `!' as in \fB-g\fR^\fIGLOB\fR, the match is+negated. Likewise, a `!' (but not a `^') may be used with globs in the files+specified \fB--include-from\fR, \fB--exclude-from\fR, and \fB--ignore-files\fR+to negate the glob match. Empty lines or lines starting with a `#' are+ignored. .PP \fBGlob Syntax and Conventions\fR .IP \fB*\fR@@ -162,17 +197,13 @@ Matches a/b, a/x/b, a/x/y/b, but not x/a/b, a/b/x Matches a/x, a/y, a/x/y, but not a, b/x .IP \fBa\\\\?b\fR Matches a?b, but not a, b, ab, axb, a/b-.PP-Lines in the \fB--exclude-from\fR and \fB--include-from\fR files are ignored-when empty or start with a `#'. When a glob is prefixed with `!', negates the-match. .SH ENVIRONMENT .IP \fBGREP_PATH\fR May be used to specify a file path to pattern files. The file path is used by option \fB-f\fR to open a pattern file, when the pattern file does not exist. .IP \fBGREP_EDITOR\fR-May be used to specify an editor command to invoke with CTRL-Y within the query-UI opened with option \fB-Q\fR. When undefined, the command defined by+May be used to specify an editor command to invoke with CTRL-Y while using the+query UI with option \fB-Q\fR. When undefined, the command defined by \fBEDITOR\fR is invoked. .IP \fBGREP_COLOR\fR May be used to specify ANSI SGR parameters to highlight matches when option@@ -184,8 +215,8 @@ May be used to specify ANSI SGR parameters to highlight matches and other attributes when option \fB--color\fR is used. Its value is a colon-separated list of ANSI SGR parameters that defaults to \fBcx=33:mt=1;31:fn=1;35:ln=1;32:cn=1;32:bn=1;32:se=36\fR. The \fBmt=\fR,-\fBms=\fR, and \fBmc=\fR capabilities of \fBGREP_COLORS\fR have priority over-\fBGREP_COLOR\fR. Option \fB--colors\fR has priority over \fBGREP_COLORS\fR.+\fBms=\fR, and \fBmc=\fR capabilities of \fBGREP_COLORS\fR take priority over+\fBGREP_COLOR\fR. Option \fB--colors\fR takes priority over \fBGREP_COLORS\fR. .SH GREP_COLORS Colors are specified as string of colon-separated ANSI SGR parameters of the form `what=substring', where `substring' is a semicolon-separated list of ANSI@@ -334,9 +365,9 @@ reverts the separator to the default separator or the separator specified with .PP 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. When field \fB%u\fR is found anywhere in the specified format string,+line. If field \fB%u\fR is specified anywhere in a format string, then matching lines are output only once unless option \fB-u\fR, \fB--ungroup\fR is-used or when a newline is matched.+specified or when one or more newlines are matched. .PP Additional formatting options: .IP \fB--format-begin\fR=\fIFORMAT\fR@@ -350,7 +381,7 @@ the \fIFORMAT\fR when ending the search. .PP The context options \fB-A\fR, \fB-B\fR, \fB-C\fR, \fB-y\fR, and options \fB-v\fR, \fB--break\fR, \fB--heading\fR, \fB--color\fR, \fB-T\fR, and-\fB--null\fR have no effect on the formatted output.+\fB--null\fR have no effect on formatted output. .SH EXAMPLES Display lines containing the word `patricia' in `myfile.txt': .IP
@@ -1,10 +1,10 @@-.TH UGREP "1" "June 29, 2020" "ugrep 2.3.2" "User Commands"+.TH UGREP "1" "July 09, 2020" "ugrep 2.4.0" "User Commands" .SH NAME-\fBugrep\fR -- file pattern searcher+\fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS .B ugrep-[\fIOPTIONS\fR] [\fB-A\fR \fINUM\fR] [\fB-B\fR \fINUM\fR] [\fB-C\fR[\fINUM\fR]] [\fIPATTERN\fR] [\fB-e\fR \fIPATTERN\fR]- [\fB-N\fR \fIPATTERN\fR] [\fB-f\fR \fIFILE\fR] [\fB-t\fR \fITYPES\fR] [\fB-J\fR [\fINUM\fR]] [\fB--sort\fR[=\fIKEY\fR]]+[\fIOPTIONS\fR] [\fB-A\fR \fINUM\fR] [\fB-B\fR \fINUM\fR] [\fB-C\fR[\fINUM\fR]] [\fIPATTERN\fR] [\fB-f\fR \fIFILE\fR]+ [\fB-e\fR \fIPATTERN\fR] [\fB-N\fR \fIPATTERN\fR] [\fB-t\fR \fITYPES\fR] [\fB-J\fR [\fINUM\fR]] [\fB--sort\fR[=\fIKEY\fR]] [\fB--color\fR[=\fIWHEN\fR]|\fB--colour\fR[=\fIWHEN\fR]] [\fB--pager\fR[=\fICOMMAND\fR]] [\fIFILE\fR \fI...\fR] .SH DESCRIPTION The \fBugrep\fR utility searches any given input files, selecting lines that@@ -14,20 +14,27 @@ input lines if the RE in the pattern matches one or more newlines in the input. An empty pattern matches every line. Each input line that matches at least one of the patterns is written to the standard output. .PP-The \fBugrep\fR utility accepts input of various encoding formats and-normalizes the output to UTF-8. When a UTF byte order mark is present in the-input, the input is automatically normalized; otherwise, \fBugrep\fR assumes-the input is ASCII, UTF-8, or raw binary. An input encoding format may be-specified with option \fB--encoding\fR.+\fBugrep\fR accepts input of various encoding formats and normalizes the output+to UTF-8. When a UTF byte order mark is present in the input, the input is+automatically normalized; otherwise, \fBugrep\fR assumes the input is ASCII,+UTF-8, or raw binary. An input encoding format may be specified with option+\fB--encoding\fR. .PP If no \fIFILE\fR arguments are specified and standard input is read from a terminal, recursive searches are performed as if \fB-R\fR is specified. To force reading from standard input, specify `-' as a \fIFILE\fR argument. .PP+Directories specified as \fIFILE\fR arguments are searched without recursing+into subdirectories, unless \fB-R\fR, \fB-r\fR, or \fB-2\fR...\fB-9\fR is+specified.+.PP Hidden files and directories are ignored in recursive searches. Option \fB-.\fR (\fB--hidden\fR) includes hidden files and directories in recursive searches. .PP+The \fBug\fR command is equivalent to \fBugrep --config\fR to load the default+configuration file, which allows for customization, see CONFIGURATION.+.PP The following options are available: .TP \fB\-A\fR \fINUM\fR, \fB\-\-after\-context\fR=\fINUM\fR@@ -99,8 +106,14 @@ bright. A foreground and a background color may be combined with font properties `n' (normal), `f' (faint), `h' (highlight), `i' (invert), `u' (underline). Selectively overrides GREP_COLORS. .TP-\fB\-\-no\-confirm\fR-Do not confirm actions in \fB\-Q\fR query mode. The default is confirm.+\fB\-\-config[\fR=\fIFILE\fR], \fB\-\-\-[\fIFILE\fR]\fR+Use configuration FILE. The default FILE is `.ugrep'. The working+directory is checked first for FILE, then the home directory. The+options specified in the configuration FILE are parsed first,+followed by the remaining options on the command line.+.TP+\fB\-\-confirm\fR+Confirm actions in \fB\-Q\fR query mode. The default is confirm. .TP \fB\-\-cpp\fR Output file matches in C++. See also options \fB\-\-format\fR and \fB\-u\fR.@@ -264,8 +277,8 @@ when there is only one file (or only standard input) to search. Group matches per file. Adds a heading and a line break between results from different files. .TP-\fB\-\-help\fR, \fB\-?\fR-Print a help message.+\fB\-\-help\fR [\fIWHAT\fR], \fB\-?\fR [\fIWHAT\fR]+Display a help message, specifically on WHAT when specified. .TP \fB\-\-hexdump\fR=[1\-8][b][c][h] Output matches in 1 to 8 columns of 8 hexadecimal octets. The@@ -276,7 +289,7 @@ hex spacing only. Enables \fB\-X\fR if \fB\-W\fR or \fB\-X\fR is not specified. \fB\-\-hidden\fR, \fB\-.\fR Search hidden files and directories. .TP-\fB\-I\fR+\fB\-I\fR, \fB\-\-ignore\-binary\fR Ignore matches in binary files. This option is equivalent to the \fB\-\-binary\-files\fR=without\-match option. .TP@@ -288,8 +301,8 @@ sensitive. This option applies to ASCII letters only. Ignore files and directories matching the globs in each FILE that is encountered in recursive searches. The default FILE is `.gitignore'. Matching files and directories located in the-directory tree rooted at a FILE's location are ignored by-temporarily overriding the \fB\-\-exclude\fR and \fB\-\-exclude\-dir\fR globs.+directory of a FILE's location and in directories below are ignored+by temporarily overriding the \fB\-\-exclude\fR and \fB\-\-exclude\-dir\fR globs. Files and directories that are explicitly specified as command line arguments are never ignored. This option may be repeated. .TP@@ -391,10 +404,10 @@ Restrict the number of files matched to NUM. Note that \fB\-\-sort\fR or \fB\-J\fR1 may be specified to produce replicable results. If \fB\-\-sort\fR is specified, the number of threads spawned is limited to NUM. .TP-\fB\-\-[no\-]mmap[\fR=\fIMAX\fR]-Do (not) use memory maps to search files. By default, memory maps-are used under certain conditions to improve performance. When MAX-is specified, use up to MAX mmap memory per thread.+\fB\-\-mmap[\fR=\fIMAX\fR]+Use memory maps to search files. By default, memory maps are used+under certain conditions to improve performance. When MAX is+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:@@ -463,7 +476,7 @@ GREP_EDIT is not defined. Enables \fB\-\-heading\fR. .TP \fB\-q\fR, \fB\-\-quiet\fR, \fB\-\-silent\fR Quiet mode: suppress all output. ugrep will only search until a-match has been found, making searches potentially less expensive.+match has been found. .TP \fB\-R\fR, \fB\-\-dereference\-recursive\fR Recursively read all files under each directory. Follow all@@ -477,9 +490,6 @@ Recursively read all files under each directory, following symbolic links only if they are on the command line. When \fB\-J\fR1 is specified, files are searched in the same order as specified. .TP-\fB\-\-range\fR=\fIFIRST\fR[,\fILAST\fR]-Start searching at line FIRST, stop at line LAST when specified.-.TP \fB\-S\fR, \fB\-\-dereference\fR If \fB\-r\fR is specified, all symbolic links are followed, like \fB\-R\fR. The default is not to follow symbolic links.@@ -488,6 +498,10 @@ default is not to follow symbolic links. Silent mode: nonexistent and unreadable files are ignored, i.e. their error messages are suppressed. .TP+\fB\-\-save\-config[\fR=\fIFILE\fR]+Save configuration FILE. By default `.ugrep' is saved. If FILE is+a `\fB\-'\fR, write the configuration to standard output.+.TP \fB\-\-separator[\fR=\fISEP\fR] Use SEP as field separator between file name, line number, column number, byte offset, and the matched line. The default is a colon@@ -629,6 +643,8 @@ arbitrary file names. A `--' signals the end of options; the rest of the parameters are \fIFILE\fR arguments, allowing filenames to begin with a `-' character. .PP+Long options may start with `\FB--no-\fR' to disable, when applicable.+.PP 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: .IP@@ -636,8 +652,7 @@ https://github.com/Genivia/ugrep .PP Note that `.' matches any non-newline character. Pattern `\\n' matches a newline character. Multiple lines may be matched with patterns that match-newlines, unless one or more of the context options \fB-A\fR, \fB-B\fR,-\fB-C\fR, or \fB-y\fR is used, or option \fB-v\fR is used.+one or more newline characters. .SH "EXIT STATUS" The \fBugrep\fR utility exits with one of the following values: .IP 0@@ -649,6 +664,30 @@ An error occurred. .PP If \fB-q\fR or \fB--quiet\fR or \fB--silent\fR is used and a line is selected, the exit status is 0 even if an error occurred.+.SH CONFIGURATION+The \fBug\fR command is intended for context-dependent interactive searching+and is equivalent to the \fBugrep --config\fR command to load the default+configuration file `.ugrep' when present in the working directory or in the+home directory.+.PP+A configuration file contains `NAME=VALUE' pairs per line, where `NAME` is the+name of a long option (without `--') and `=VALUE' is an argument, which is+optional and may be omitted depending on the option. Empty lines and lines+starting with a `#' are ignored.+.PP+The \fB--config\fR=\fIFILE\fR option and its abbreviated form+\fB---\fR\fIFILE\fR load the specified configuration file located in the+working directory or, when not found, located in the home directory. An error+is produced when \fIFILE\fR is not found or cannot be read.+.PP+Command line options are parsed in the following order: the configuration file+is loaded first, followed by the remaining options and arguments on the command+line.+.PP+The \fB--save-config\fR option saves a `.ugrep' configuration file to the+working directory with a subset of the current options. The+\fB--save-config\fR=\fIFILE\fR option saves the configuration to \fIFILE\fR.+The configuration is written to standard output when \fIFILE\fR is a `-'. .SH GLOBBING Globbing is used by options \fB-g\fR, \fB--include\fR, \fB--include-dir\fR, \fB--include-from\fR, \fB--exclude\fR, \fB--exclude-dir\fR,@@ -657,14 +696,16 @@ Globbing supports gitignore syntax and the corresponding matching rules. When a glob ends in a path separator it matches directories as if \fB--include-dir\fR or \fB--exclude-dir\fR is specified. When a glob contains a path separator `/', the full pathname is matched. Otherwise the basename of-a file or directory is matched. For example, \fB*.h\fR matches \fIfoo.h\fR and-\fIbar/foo.h\fR. \fBbar/*.h\fR matches \fIbar/foo.h\fR but not \fIfoo.h\fR and-not \fIbar/bar/foo.h\fR. Use a leading `/' to force \fB/*.h\fR to match-\fIfoo.h\fR but not \fIbar/foo.h\fR.+a file or directory is matched. For example, \fB*.h\fR matches foo.h and+bar/foo.h. \fBbar/*.h\fR matches bar/foo.h but not foo.h and not+bar/bar/foo.h. Use a leading `/' to force \fB/*.h\fR to match foo.h but not+bar/foo.h. .PP-When a glob starts with a `!' as specified with \fB-g\fR!\fIGLOB\fR, or-specified in a \fIFILE\fR with \fB--include-from\fR=\fIFILE\fR or-\fB--exclude-from\fR=\fIFILE\fR, its match is negated.+When a glob starts with a `^' or a `!' as in \fB-g\fR^\fIGLOB\fR, the match is+negated. Likewise, a `!' (but not a `^') may be used with globs in the files+specified \fB--include-from\fR, \fB--exclude-from\fR, and \fB--ignore-files\fR+to negate the glob match. Empty lines or lines starting with a `#' are+ignored. .PP \fBGlob Syntax and Conventions\fR .IP \fB*\fR@@ -716,17 +757,13 @@ Matches a/b, a/x/b, a/x/y/b, but not x/a/b, a/b/x Matches a/x, a/y, a/x/y, but not a, b/x .IP \fBa\\\\?b\fR Matches a?b, but not a, b, ab, axb, a/b-.PP-Lines in the \fB--exclude-from\fR and \fB--include-from\fR files are ignored-when empty or start with a `#'. When a glob is prefixed with `!', negates the-match. .SH ENVIRONMENT .IP \fBGREP_PATH\fR May be used to specify a file path to pattern files. The file path is used by option \fB-f\fR to open a pattern file, when the pattern file does not exist. .IP \fBGREP_EDITOR\fR-May be used to specify an editor command to invoke with CTRL-Y within the query-UI opened with option \fB-Q\fR. When undefined, the command defined by+May be used to specify an editor command to invoke with CTRL-Y while using the+query UI with option \fB-Q\fR. When undefined, the command defined by \fBEDITOR\fR is invoked. .IP \fBGREP_COLOR\fR May be used to specify ANSI SGR parameters to highlight matches when option@@ -738,8 +775,8 @@ May be used to specify ANSI SGR parameters to highlight matches and other attributes when option \fB--color\fR is used. Its value is a colon-separated list of ANSI SGR parameters that defaults to \fBcx=33:mt=1;31:fn=1;35:ln=1;32:cn=1;32:bn=1;32:se=36\fR. The \fBmt=\fR,-\fBms=\fR, and \fBmc=\fR capabilities of \fBGREP_COLORS\fR have priority over-\fBGREP_COLOR\fR. Option \fB--colors\fR has priority over \fBGREP_COLORS\fR.+\fBms=\fR, and \fBmc=\fR capabilities of \fBGREP_COLORS\fR take priority over+\fBGREP_COLOR\fR. Option \fB--colors\fR takes priority over \fBGREP_COLORS\fR. .SH GREP_COLORS Colors are specified as string of colon-separated ANSI SGR parameters of the form `what=substring', where `substring' is a semicolon-separated list of ANSI@@ -888,9 +925,9 @@ reverts the separator to the default separator or the separator specified with .PP 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. When field \fB%u\fR is found anywhere in the specified format string,+line. If field \fB%u\fR is specified anywhere in a format string, then matching lines are output only once unless option \fB-u\fR, \fB--ungroup\fR is-used or when a newline is matched.+specified or when one or more newlines are matched. .PP Additional formatting options: .IP \fB--format-begin\fR=\fIFORMAT\fR@@ -904,7 +941,7 @@ the \fIFORMAT\fR when ending the search. .PP The context options \fB-A\fR, \fB-B\fR, \fB-C\fR, \fB-y\fR, and options \fB-v\fR, \fB--break\fR, \fB--heading\fR, \fB--color\fR, \fB-T\fR, and-\fB--null\fR have no effect on the formatted output.+\fB--null\fR have no effect on formatted output. .SH EXAMPLES Display lines containing the word `patricia' in `myfile.txt': .IP
@@ -231,6 +231,7 @@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@+LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@
@@ -1971,7 +1971,7 @@ void Query::edit() // quit ugrep -Q bool Query::quit() {- if (flag_no_confirm)+ if (!flag_confirm) return true; if (!Screen::mono)
@@ -59,54 +59,56 @@ void Stats::report() if (warnings > 0) fprintf(output, "Received %zu warning%s\n", ws, ws == 1 ? "" : "s"); fprintf(output, "The following pathname selections and restrictions were applied:\n");+ if (flag_config != NULL)+ fprintf(output, " --config=%s\n", flag_config_file.c_str()); #ifdef WITH_HIDDEN if (flag_hidden)- fprintf(output, "--hidden (default)\n");+ fprintf(output, " --hidden (default)\n"); else- fprintf(output, "--no-hidden\n");+ fprintf(output, " --no-hidden\n"); #else if (flag_hidden)- fprintf(output, "--hidden\n");+ fprintf(output, " --hidden\n"); else- fprintf(output, "--no-hidden (default)\n");+ fprintf(output, " --no-hidden (default)\n"); #endif if (flag_min_depth > 0 && flag_max_depth > 0)- fprintf(output, "--depth=%zu,%zu\n", flag_min_depth, flag_max_depth);+ fprintf(output, " --depth=%zu,%zu\n", flag_min_depth, flag_max_depth); else if (flag_min_depth > 0)- fprintf(output, "--depth=%zu,\n", flag_min_depth);+ fprintf(output, " --depth=%zu,\n", flag_min_depth); else if (flag_max_depth > 0)- fprintf(output, "--depth=%zu\n", flag_max_depth);+ fprintf(output, " --depth=%zu\n", flag_max_depth); for (auto& i : flag_ignore_files)- fprintf(output, "--ignore-files='%s'\n", i.c_str());+ fprintf(output, " --ignore-files='%s'\n", i.c_str()); for (auto& i : ignore)- fprintf(output, " %s exclusions were applied to %s\n", i.c_str(), i.substr(0, i.find_last_of(PATHSEPCHR)).c_str());+ fprintf(output, " %s exclusions were applied to %s\n", i.c_str(), i.substr(0, i.find_last_of(PATHSEPCHR)).c_str()); for (auto& i : flag_file_magic) { if (!i.empty() && (i.front() == '!' || i.front() == '^'))- fprintf(output, "--file-magic='!%s' (negation)\n", i.c_str() + 1);+ fprintf(output, " --file-magic='!%s' (negation)\n", i.c_str() + 1); else- fprintf(output, "--file-magic='%s'\n", i.c_str());+ fprintf(output, " --file-magic='%s'\n", i.c_str()); } for (auto& i : flag_all_include)- fprintf(output, "--include='%s'\n", i.c_str());+ fprintf(output, " --include='%s'\n", i.c_str()); for (auto& i : flag_not_include)- fprintf(output, "--include='!%s' (negation)\n", i.c_str());+ fprintf(output, " --include='!%s' (negation)\n", i.c_str()); for (auto& i : flag_include_fs)- fprintf(output, "--include-fs='%s'\n", i.c_str());+ fprintf(output, " --include-fs='%s'\n", i.c_str()); for (auto& i : flag_all_include_dir)- fprintf(output, "--include-dir='%s'\n", i.c_str());+ fprintf(output, " --include-dir='%s'\n", i.c_str()); for (auto& i : flag_not_include_dir)- fprintf(output, "--include-dir='!%s' (negation)\n", i.c_str());+ fprintf(output, " --include-dir='!%s' (negation)\n", i.c_str()); for (auto& i : flag_all_exclude)- fprintf(output, "--exclude='%s'\n", i.c_str());+ fprintf(output, " --exclude='%s'\n", i.c_str()); for (auto& i : flag_not_exclude)- fprintf(output, "--exclude='!%s' (negation)\n", i.c_str());+ fprintf(output, " --exclude='!%s' (negation)\n", i.c_str()); for (auto& i : flag_exclude_fs)- fprintf(output, "--exclude-fs='%s'\n", i.c_str());+ fprintf(output, " --exclude-fs='%s'\n", i.c_str()); for (auto& i : flag_all_exclude_dir)- fprintf(output, "--exclude-dir='%s'\n", i.c_str());+ fprintf(output, " --exclude-dir='%s'\n", i.c_str()); for (auto& i : flag_not_exclude_dir)- fprintf(output, "--exclude-dir='!%s' (negation)\n", i.c_str());+ fprintf(output, " --exclude-dir='!%s' (negation)\n", i.c_str()); } size_t Stats::files = 0;
@@ -67,7 +67,7 @@ After this, you may want to test ugrep and install it (optional): */ // ugrep version-#define UGREP_VERSION "2.3.2"+#define UGREP_VERSION "2.4.0" #include "ugrep.hpp" #include "glob.hpp"@@ -83,12 +83,12 @@ After this, you may want to test ugrep and install it (optional): #include <functional> #include <list> #include <deque>-#include <set> #include <thread> #include <memory> #include <mutex> #include <condition_variable> #include <chrono>+#include <sstream> #ifdef OS_WIN @@ -309,6 +309,9 @@ static void sigint(int sig) #endif +// full home directory path+const char *home_dir = NULL;+ // ANSI SGR substrings extracted from GREP_COLORS char color_sl[COLORLEN]; // selected line char color_cx[COLORLEN]; // context line@@ -372,7 +375,6 @@ std::set<uint64_t> exclude_fs_ids, include_fs_ids; #endif // ugrep command-line options and internal flags-bool flag_no_confirm = false; bool flag_no_header = false; bool flag_no_messages = false; bool flag_match = false;@@ -420,6 +422,7 @@ bool flag_all_threads = false; bool flag_heading = false; bool flag_pretty = DEFAULT_PRETTY; bool flag_hidden = DEFAULT_HIDDEN;+bool flag_confirm = true; bool flag_hex_hbr = true; bool flag_hex_cbr = true; bool flag_hex_chr = true;@@ -465,6 +468,10 @@ const char *flag_label = "(standard input)"; const char *flag_separator = ":"; const char *flag_group_separator = "--"; const char *flag_binary_files = "binary";+const char *flag_config = NULL;+const char *flag_save_config = NULL;+std::string flag_config_file;+std::set<std::string> flag_config_options; std::vector<std::string> flag_regexp; std::vector<std::string> flag_neg_regexp; std::vector<std::string> flag_file;@@ -506,12 +513,31 @@ size_t strtofuzzy(const char *string, const char *message); void extend(FILE *file, std::vector<std::string>& files, std::vector<std::string>& dirs, std::vector<std::string>& not_files, std::vector<std::string>& not_dirs); void format(const char *format, size_t matches);-void help(const char *message, const char *arg = NULL, const char *valid = NULL);-void help();+void usage(const char *message, const char *arg = NULL, const char *valid = NULL);+void help(std::ostream& out);+void help(const char *what = NULL); void version(); void is_directory(const char *pathname); void cannot_decompress(const char *pathname, const char *message); +// open a file where - means stdin/stdout and ~ expands to home directory+int fopen_smart(FILE **file, const char *filename, const char *mode)+{+ if (filename == NULL || *filename == '\0')+ return errno = ENOENT;++ if (strcmp(filename, "-") == 0)+ {+ *file = strchr(mode, 'w') == NULL ? stdin : stdout;+ return 0;+ }++ if (*filename == '~')+ return fopen_s(file, std::string(home_dir).append(filename + 1).c_str(), mode);++ return fopen_s(file, filename, mode);+}+ // read a line from buffered input, returns true when eof inline bool getline(reflex::BufferedInput& input, std::string& line) {@@ -2857,7 +2883,7 @@ struct GrepWorker : public Grep { bool inserted = false; // insert job in the queue to maintain job order- for (std::deque<Job>::iterator j = jobs.begin(); j != jobs.end(); ++j)+ for (auto j = jobs.begin(); j != jobs.end(); ++j) { if (j->slot > job.slot) {@@ -2986,7 +3012,7 @@ bool GrepMaster::steal(GrepWorker *worker) { // pick a random co-worker using thread-safe std::chrono::high_resolution_clock as a simple RNG size_t n = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count() % threads;- std::list<GrepWorker>::iterator iworker = workers.begin();+ auto iworker = workers.begin(); while (n > 0) {@@ -3204,7 +3230,7 @@ const Type type_table[] = { }; // function protos for functions used in main()-void options(int argc, const char **argv);+void init(int argc, const char **argv); // ugrep main() int main(int argc, const char **argv)@@ -3249,7 +3275,7 @@ int main(int argc, const char **argv) try {- options(argc, argv);+ init(argc, argv); } catch (std::exception& error)@@ -3296,7 +3322,7 @@ static void set_depth(const char *arg) flag_min_depth = flag_max_depth; flag_max_depth = strtopos(arg, "invalid argument --"); if (flag_min_depth > flag_max_depth)- help("invalid argument -", arg);+ usage("invalid argument -", arg); } else {@@ -3304,58 +3330,180 @@ static void set_depth(const char *arg) } } -// parse the command-line options-void options(int argc, const char **argv)+void options(int argc, const char **argv);++// load config file specified or the default .ugrep, located in the working directory or home directory+static void load_config() {- // automatically apply the appropriate options when the program is named grep, egrep, or fgrep+ // the default config file is .ugrep when FILE is not specified+ if (flag_config == NULL || *flag_config == '\0')+ flag_config_file.assign(".ugrep");+ else+ flag_config_file.assign(flag_config); - const char *program = strrchr(argv[0], PATHSEPCHR);+ FILE *file = NULL; - if (program == NULL)- program = argv[0];- else- ++program;+ if (fopen_smart(&file, flag_config_file.c_str(), "r") != 0)+ {+ if (home_dir != NULL)+ {+ // check the home directory for the configuration file+ if (flag_config == NULL || *flag_config == '\0')+ flag_config_file.assign(home_dir).append(PATHSEPSTR).append(".ugrep");+ else+ flag_config_file.assign(home_dir).append(PATHSEPSTR).append(flag_config);+ if (fopen_smart(&file, flag_config_file.c_str(), "r") != 0)+ file = NULL;+ }+ } - if (strcmp(program, "grep") == 0)+ if (file != NULL) {- flag_basic_regexp = true;- flag_hidden = true;- flag_empty = true;+ reflex::BufferedInput input(file);++ std::string line;+ size_t lineno = 1;++ while (true)+ {+ // read the next line+ if (getline(input, line))+ break;++ trim(line);++ // skip empty lines and comments+ if (line.empty() || line.front() == '#')+ continue;++ // construct an option argument and make it persistent (to parse as argv[])+ line.insert(0, "--");+ const char *arg = flag_config_options.insert(line).first->c_str();+ const char *args[2] = { NULL, arg };++ warnings = 0;++ options(2, args);++ if (warnings > 0)+ {+ std::cerr << "ugrep: error in " << flag_config_file << " at line " << lineno << std::endl;+ std::cerr << "Try 'ugrep --help [WHAT]' for more information\n";++ exit(EXIT_ERROR);+ }++ ++lineno;+ }++ if (file != stdin)+ fclose(file);++ if (ferror(file))+ error("error while reading", flag_config_file.c_str()); }- else if (strcmp(program, "egrep") == 0)+ else if (flag_config != NULL && *flag_config != '\0') {- flag_hidden = true;- flag_empty = true;+ error("cannot read", flag_config_file.c_str()); }- else if (strcmp(program, "fgrep") == 0)+}++// save a configuration file+static void save_config()+{+ FILE *file = NULL;++ if (fopen_smart(&file, flag_save_config, "w") != 0) {- flag_fixed_strings = true;- flag_hidden = true;- flag_empty = true;+ usage("cannot save configuration file ", flag_save_config);++ return; }- else if (strcmp(program, "zgrep") == 0)++ if (strcmp(flag_save_config, ".ugrep") == 0)+ fprintf(file, "# default .ugrep configuration file used by ug and ugrep --config.\n");+ else if (strcmp(flag_save_config, "-") == 0)+ fprintf(file, "# ugrep configuration.\n");+ else+ fprintf(file, "# configuration %s used with ugrep ---%s.\n", flag_save_config, flag_save_config);++ fprintf(file, "\+#\n\+# A long option is defined per line with an optional `=' and its argument,\n\+# when applicable. Empty lines and lines starting with a `#' are ignored.\n\+#\n\+# Try `ugrep --help [WHAT]' for more information.\n\n");++ fprintf(file, "### TERMINAL DISPLAY ###\n\n");++ fprintf(file, "# Custom color scheme overrides the default GREP_COLORS parameters\ncolors=%s\n", flag_colors != NULL ? flag_colors : "");+ fprintf(file, "\+# The argument is a colon-separated list of one or more parameters `sl='\n\+# (selected line), `cx=' (context line), `mt=' (matched text), `ms=' (match\n\+# selected), `mc=' (match context), `fn=' (file name), `ln=' (line number),\n\+# `cn=' (column number), `bn=' (byte offset), `se=' (separator). Parameter\n\+# values are ANSI SGR color codes or `k' (black), `r' (red), `g' (green), `y'\n\+# (yellow), `b' (blue), `m' (magenta), `c' (cyan), `w' (white). Upper case\n\+# specifies background colors. A `+' qualifies a color as bright. A\n\+# foreground and a background color may be combined with font properties `n'\n\+# (normal), `f' (faint), `h' (highlight), `i' (invert), `u' (underline).\n\n");+ fprintf(file, "# Enable/disable color\n%s\n\n", flag_color != NULL ? "color" : "no-color");+ fprintf(file, "# Enable/disable query UI confirm ESC to exit y/n\n%s\n\n", flag_confirm ? "confirm" : "no-confirm");+ fprintf(file, "# Enable/disable headings for terminal output\n%s\n\n", flag_heading ? "heading" : "no-heading");+ fprintf(file, "# Enable/disable or specify a preferred pager for terminal output\n%s\n\n", flag_pager != NULL ? flag_pager : "no-pager");+ fprintf(file, "# Enable/disable pretty output to the terminal\n%s\n\n", flag_pretty ? "pretty" : "no-pretty");++ fprintf(file, "### SEARCH PATTERNS ###\n\n");++ fprintf(file, "# Enable/disable case-insensitive search by default\n%s\n\n", flag_ignore_case ? "ignore-case" : "no-ignore-case");+ fprintf(file, "# Enable/disable smart case by default\n%s\n\n", flag_smart_case ? "smart-case" : "no-smart-case");++ fprintf(file, "### SEARCH TARGETS ###\n\n");++ fprintf(file, "# Enable/disable searching hidden files and directories\n%s\n\n", flag_hidden ? "hidden" : "no-hidden");+ fprintf(file, "# Enable/disable binary files\n%s\n\n", strcmp(flag_binary_files, "without-match") == 0 ? "ignore-binary" : "no-ignore-binary");+ fprintf(file, "# Enable/disable decompression and archive search by default\n%s\n\n", flag_decompress ? "decompress" : "no-decompress");+ if (flag_ignore_files.empty()) {- flag_decompress = true;- flag_basic_regexp = true;- flag_hidden = true;- flag_empty = true;+ fprintf(file, "# Enable/disable ignore files by default\nno-ignore-files\n\n"); }- else if (strcmp(program, "zegrep") == 0)+ else {- flag_decompress = true;- flag_hidden = true;- flag_empty = true;+ fprintf(file, "# Enable/disable ignore files by default\n");+ for (auto& ignore : flag_ignore_files)+ fprintf(file, "ignore-files=%s\n", ignore.c_str());+ fprintf(file, "\n"); }- else if (strcmp(program, "zfgrep") == 0)+ if (flag_filter != NULL)+ fprintf(file, "# Filtering\nfilter=%s\n\n", flag_filter);+ else+ fprintf(file, "# Search PDF files by writing them as text to stdout with the pdftotext utility\n# filter=pdf:pdftotext %% -\n");+ if (!flag_filter_magic_label.empty()) {- flag_decompress = true;- flag_fixed_strings = true;- flag_hidden = true;- flag_empty = true;+ fprintf(file, "# Filter by file signature magic bytes\n");+ for (auto& label : flag_filter_magic_label)+ fprintf(file, "filter-magic-label=%s\n", label.c_str()); }+ else+ {+ fprintf(file, "# Search any PDF file even when no pdf extension is present\n# filter-magic-label=pdf:%%PDF-\n");+ }+ fprintf(file, "# Warning: filter-magic-label significantly reduces performance!\n\n"); - // parse ugrep command-line options and arguments+ fprintf(file, "### OUTPUT ###\n\n");++ fprintf(file, "# Enable/disable sorted output\n%s\n\n", flag_sort != NULL ? flag_sort : "no-sort"); + if (file != stdout)+ fclose(file);++ if (ferror(file))+ error("cannot save", flag_save_config);+}++// parse the command-line options+void options(int argc, const char **argv)+{ bool options = true; for (int i = 1; i < argc; ++i)@@ -3385,15 +3533,18 @@ void options(int argc, const char **argv) switch (*arg) {+ case '-':+ break;+ case 'a': if (strncmp(arg, "after-context=", 14) == 0) flag_after_context = strtopos(arg + 14, "invalid argument --after-context="); else if (strcmp(arg, "any-line") == 0) flag_any_line = true; else if (strcmp(arg, "after-context") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--after-context or --any-line");+ usage("invalid option --", arg, "--after-context or --any-line"); break; case 'b':@@ -3410,9 +3561,9 @@ void options(int argc, const char **argv) else if (strcmp(arg, "byte-offset") == 0) flag_byte_offset = true; else if (strcmp(arg, "before-context") == 0 || strcmp(arg, "binary-files") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--basic-regexp, --before-context, --binary, --binary-files, --break or --byte-offset");+ usage("invalid option --", arg, "--basic-regexp, --before-context, --binary, --binary-files, --break or --byte-offset"); break; case 'c':@@ -3428,8 +3579,12 @@ void options(int argc, const char **argv) flag_colors = arg + 8; else if (strcmp(arg, "column-number") == 0) flag_column_number = true;+ else if (strcmp(arg, "config") == 0)+ ;+ else if (strncmp(arg, "config=", 7) == 0)+ ; else if (strcmp(arg, "confirm") == 0)- flag_no_confirm = false;+ flag_confirm = true; else if (strcmp(arg, "context") == 0) flag_after_context = flag_before_context = 2; else if (strncmp(arg, "context=", 8) == 0)@@ -3441,9 +3596,9 @@ void options(int argc, const char **argv) else if (strcmp(arg, "csv") == 0) flag_csv = true; else if (strcmp(arg, "colors") == 0 || strcmp(arg, "colours") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--color, --colors, --column-number, --confirm, --context, --count, --cpp or --csv");+ usage("invalid option --", arg, "--color, --colors, --column-number, --config, --confirm, --context, --count, --cpp or --csv"); break; case 'd':@@ -3460,9 +3615,9 @@ void options(int argc, const char **argv) else if (strncmp(arg, "directories=", 12) == 0) flag_directories = arg + 12; else if (strcmp(arg, "depth") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--decompress, --depth, --dereference, --dereference-recursive, --devices or --directories");+ usage("invalid option --", arg, "--decompress, --depth, --dereference, --dereference-recursive, --devices or --directories"); break; case 'e':@@ -3485,9 +3640,9 @@ void options(int argc, const char **argv) strcmp(arg, "exclude-dir") == 0 || strcmp(arg, "exclude-from") == 0 || strcmp(arg, "exclude-fs") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--empty, --encoding, --exclude, --exclude-dir, --exclude-from, --exclude-fs or --extended-regexp");+ usage("invalid option --", arg, "--empty, --encoding, --exclude, --exclude-dir, --exclude-from, --exclude-fs or --extended-regexp"); break; case 'f':@@ -3536,9 +3691,9 @@ void options(int argc, const char **argv) strcmp(arg, "format-close") == 0 || strcmp(arg, "format-end") == 0 || strcmp(arg, "format-open") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--file, --file-extension, --file-magic, --file-type, --files-with-matches, --files-without-match, --fixed-strings, --filter, --filter-magic-label, --format, --format-begin, --format-close, --format-end, --format-open, --fuzzy or --free-space");+ usage("invalid option --", arg, "--file, --file-extension, --file-magic, --file-type, --files-with-matches, --files-without-match, --fixed-strings, --filter, --filter-magic-label, --format, --format-begin, --format-close, --format-end, --format-open, --fuzzy or --free-space"); break; case 'g':@@ -3549,16 +3704,16 @@ void options(int argc, const char **argv) else if (strcmp(arg, "group-separator") == 0) flag_group_separator = "--"; else if (strcmp(arg, "glob") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--glob or --group-separator");+ usage("invalid option --", arg, "--glob or --group-separator"); break; case 'h': if (strcmp(arg, "heading") == 0) flag_heading = true;- else if (strcmp(arg, "help") == 0)- help();+ else if (strncmp(arg, "help", 4) == 0)+ help(arg[4] != '\0' ? arg + 4 : ++i < argc ? argv[i] : NULL); else if (strcmp(arg, "hex") == 0) flag_binary_files = "hex"; else if (strcmp(arg, "hexdump") == 0)@@ -3568,11 +3723,13 @@ void options(int argc, const char **argv) else if (strcmp(arg, "hidden") == 0) flag_hidden = true; else- help("invalid option --", arg, "--heading, --help, --hex, --hexdump or --hidden");+ usage("invalid option --", arg, "--heading, --help, --hex, --hexdump or --hidden"); break; case 'i':- if (strcmp(arg, "ignore-case") == 0)+ if (strcmp(arg, "ignore-binary") == 0)+ flag_binary_files = "without-match";+ else if (strcmp(arg, "ignore-case") == 0) flag_ignore_case = true; else if (strcmp(arg, "ignore-files") == 0) flag_ignore_files.emplace_back(DEFAULT_IGNORE_FILE);@@ -3594,9 +3751,9 @@ void options(int argc, const char **argv) strcmp(arg, "include-dir") == 0 || strcmp(arg, "include-from") == 0 || strcmp(arg, "include-fs") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--ignore-case, --ignore-files, --include, --include-dir, --include-from, --include-fs, --initial-tab or --invert-match");+ usage("invalid option --", arg, "--ignore-case, --ignore-files, --include, --include-dir, --include-from, --include-fs, --initial-tab or --invert-match"); break; case 'j':@@ -3605,9 +3762,9 @@ void options(int argc, const char **argv) else if (strcmp(arg, "json") == 0) flag_json = true; else if (strcmp(arg, "jobs") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--jobs or --json");+ usage("invalid option --", arg, "--jobs or --json"); break; case 'l':@@ -3620,7 +3777,7 @@ void options(int argc, const char **argv) else if (strcmp(arg, "line-regexp") == 0) flag_line_regexp = true; else- help("invalid option --", arg, "--label, --line-buffered, --line-number or --line-regexp");+ usage("invalid option --", arg, "--label, --line-buffered, --line-number or --line-regexp"); break; case 'm':@@ -3636,21 +3793,35 @@ void options(int argc, const char **argv) flag_max_mmap = MAX_MMAP_SIZE; else if (strncmp(arg, "mmap=", 5) == 0) flag_max_mmap = strtopos(arg + 5, "invalid argument --mmap=");+ else if (strcmp(arg, "messages") == 0)+ flag_no_messages = false; else if (strcmp(arg, "max-count") == 0 || strcmp(arg, "max-files") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--match, --max-count, --max-files or --mmap");+ usage("invalid option --", arg, "--match, --max-count, --max-files or --mmap"); break; case 'n': if (strncmp(arg, "neg-regexp=", 11) == 0) flag_neg_regexp.emplace_back(arg + 11);+ else if (strcmp(arg, "no-any-line") == 0)+ flag_any_line = false;+ else if (strcmp(arg, "no-binary") == 0)+ flag_binary = false;+ else if (strcmp(arg, "no-byte-offset") == 0)+ flag_byte_offset = false; else if (strcmp(arg, "no-color") == 0 || strcmp(arg, "no-colour") == 0) flag_color = "never";+ else if (strcmp(arg, "no-column-number") == 0)+ flag_column_number = false; else if (strcmp(arg, "no-confirm") == 0)- flag_no_confirm = true;+ flag_confirm = false;+ else if (strcmp(arg, "no-decompress") == 0)+ flag_decompress = false; else if (strcmp(arg, "no-dereference") == 0) flag_no_dereference = true;+ else if (strcmp(arg, "no-empty") == 0)+ flag_empty = false; else if (strcmp(arg, "no-filename") == 0) flag_no_filename = true; else if (strcmp(arg, "no-group-separator") == 0)@@ -3659,6 +3830,22 @@ void options(int argc, const char **argv) flag_heading = false; else if (strcmp(arg, "no-hidden") == 0) flag_hidden = false;+ else if (strcmp(arg, "no-ignore-binary") == 0)+ flag_binary_files = "binary";+ else if (strcmp(arg, "no-ignore-case") == 0)+ flag_ignore_case = false;+ else if (strcmp(arg, "no-ignore-files") == 0)+ flag_ignore_files.clear();+ else if (strcmp(arg, "no-ignore-initial-tab") == 0)+ flag_initial_tab = false;+ else if (strcmp(arg, "no-invert-match") == 0)+ flag_invert_match = false;+ else if (strcmp(arg, "no-line-number") == 0)+ flag_line_number = false;+ else if (strcmp(arg, "no-only-line-number") == 0)+ flag_only_line_number = false;+ else if (strcmp(arg, "no-only-matching") == 0)+ flag_only_matching = false; else if (strcmp(arg, "no-messages") == 0) flag_no_messages = true; else if (strcmp(arg, "no-mmap") == 0)@@ -3667,12 +3854,20 @@ void options(int argc, const char **argv) flag_pager = NULL; else if (strcmp(arg, "no-pretty") == 0) flag_pretty = false;+ else if (strcmp(arg, "no-smart-case") == 0)+ flag_smart_case = false;+ else if (strcmp(arg, "no-sort") == 0)+ flag_sort = NULL;+ else if (strcmp(arg, "no-stats") == 0)+ flag_stats = NULL;+ else if (strcmp(arg, "no-ungroup") == 0)+ flag_ungroup = false; else if (strcmp(arg, "null") == 0) flag_null = true; else if (strcmp(arg, "neg-regexp") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--neg-regexp, --no-color, --no-confirm, --no-dereference, --no-filename, --no-group-separator, --no-heading, --no-hidden, --no-messages, --no-mmap, --no-pager, --no-pretty or --null");+ usage("invalid option --", arg, "--neg-regexp, --no-any-line, --no-binary, --no-byte-offset, --no-color, --no-confirm, --no-decompress, --no-dereference, --no-empty, --no-filename, --no-group-separator, --no-heading, --no-hidden, --no-ignore-binary, --no-ignore-case, --no-ignore-files --no-ignore-initial-tab, --no-invert-match, --no-line-number, --no-only-line-number, --no-only-matching, --no-messages, --no-mmap, --no-pager, --no-pretty, --no-smart-case, --no-sort, --no-stats, --no-ungroup or --null"); break; case 'o':@@ -3681,7 +3876,7 @@ void options(int argc, const char **argv) else if (strcmp(arg, "only-matching") == 0) flag_only_matching = true; else- help("invalid option --", arg, "--only-line-number or --only-matching");+ usage("invalid option --", arg, "--only-line-number or --only-matching"); break; case 'p':@@ -3694,7 +3889,7 @@ void options(int argc, const char **argv) else if (strcmp(arg, "pretty") == 0) flag_pretty = true; else- help("invalid option --", arg, "--pager, --perl-regexp or --pretty");+ usage("invalid option --", arg, "--pager, --perl-regexp or --pretty"); break; case 'q':@@ -3705,7 +3900,7 @@ void options(int argc, const char **argv) else if (strcmp(arg, "quiet") == 0) flag_quiet = flag_no_messages = true; else- help("invalid option --", arg, "--query or --quiet");+ usage("invalid option --", arg, "--query or --quiet"); break; case 'r':@@ -3716,13 +3911,17 @@ void options(int argc, const char **argv) else if (strncmp(arg, "regexp=", 7) == 0) flag_regexp.emplace_back(arg + 7); else if (strcmp(arg, "range") == 0)- help("missing argument for --", arg);+ usage("missing argument for --", arg); else- help("invalid option --", arg, "--range, --recursive or --regexp");+ usage("invalid option --", arg, "--range, --recursive or --regexp"); break; case 's':- if (strcmp(arg, "separator") == 0)+ if (strcmp(arg, "save-config") == 0)+ flag_save_config = ".ugrep";+ else if (strncmp(arg, "save-config=", 12) == 0)+ flag_save_config = arg + 12;+ else if (strcmp(arg, "separator") == 0) flag_separator = ":"; else if (strncmp(arg, "separator=", 10) == 0) flag_separator = arg + 10;@@ -3739,7 +3938,7 @@ void options(int argc, const char **argv) else if (strncmp(arg, "stats=", 6) == 0) flag_stats = arg + 6; else- help("invalid option --", arg, "--separator, --silent, --smart-case, --sort or --stats");+ usage("invalid option --", arg, "--save-config, --separator, --silent, --smart-case, --sort or --stats"); break; case 't':@@ -3754,21 +3953,21 @@ void options(int argc, const char **argv) else if (strcmp(arg, "text") == 0) flag_binary_files = "text"; else- help("invalid option --", arg, "--tabs, --tag or --text");+ usage("invalid option --", arg, "--tabs, --tag or --text"); break; case 'u': if (strcmp(arg, "ungroup") == 0) flag_ungroup = true; else- help("invalid option --", arg, "--ungroup");+ usage("invalid option --", arg, "--ungroup"); break; case 'v': if (strcmp(arg, "version") == 0) version(); else- help("invalid option --", arg, "--version");+ usage("invalid option --", arg, "--version"); break; case 'w':@@ -3779,21 +3978,21 @@ void options(int argc, const char **argv) else if (strcmp(arg, "word-regexp") == 0) flag_word_regexp = true; else- help("invalid option --", arg, "--with-filename, --with-hex or --word-regexp");+ usage("invalid option --", arg, "--with-filename, --with-hex or --word-regexp"); break; case 'x': if (strcmp(arg, "xml") == 0) flag_xml = true; else- help("invalid option --", arg, "--xml");+ usage("invalid option --", arg, "--xml"); break; default: if (isdigit(*arg)) set_depth(arg); else- help("invalid option --", arg);+ usage("invalid option --", arg); } break; @@ -3804,7 +4003,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_after_context = strtopos(argv[i], "invalid argument -A="); else- help("missing NUM argument for option -A");+ usage("missing NUM argument for option -A"); is_grouped = false; break; @@ -3819,7 +4018,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_before_context = strtopos(argv[i], "invalid argument -B="); else- help("missing NUM argument for option -B");+ usage("missing NUM argument for option -B"); is_grouped = false; break; @@ -3852,7 +4051,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_devices = argv[i]; else- help("missing ACTION argument for option -D");+ usage("missing ACTION argument for option -D"); is_grouped = false; break; @@ -3863,7 +4062,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_directories = argv[i]; else- help("missing ACTION argument for option -d");+ usage("missing ACTION argument for option -d"); is_grouped = false; break; @@ -3878,7 +4077,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_regexp.emplace_back(argv[i]); else- help("missing PATTERN argument for option -e");+ usage("missing PATTERN argument for option -e"); is_grouped = false; break; @@ -3893,7 +4092,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_file.emplace_back(argv[i]); else- help("missing FILE argument for option -f");+ usage("missing FILE argument for option -f"); is_grouped = false; break; @@ -3908,7 +4107,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_glob.emplace_back(argv[i]); else- help("missing GLOB argument for option -g");+ usage("missing GLOB argument for option -g"); is_grouped = false; break; @@ -3935,7 +4134,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_jobs = strtonum(argv[i], "invalid argument -J="); else- help("missing NUM argument for option -J");+ usage("missing NUM argument for option -J"); is_grouped = false; break; @@ -3950,7 +4149,7 @@ void options(int argc, const char **argv) else if (++i < argc) strtopos2(argv[i], flag_min_line, flag_max_line, "invalid argument -K="); else- help("missing NUM argument for option -K");+ usage("missing NUM argument for option -K"); is_grouped = false; break; @@ -3973,7 +4172,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_file_magic.emplace_back(argv[i]); else- help("missing MAGIC argument for option -M");+ usage("missing MAGIC argument for option -M"); is_grouped = false; break; @@ -3984,7 +4183,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_max_count = strtopos(argv[i], "invalid argument -m="); else- help("missing NUM argument for option -m");+ usage("missing NUM argument for option -m"); is_grouped = false; break; @@ -3995,7 +4194,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_neg_regexp.emplace_back(argv[i]); else- help("missing PATTERN argument for option -N");+ usage("missing PATTERN argument for option -N"); is_grouped = false; break; @@ -4010,7 +4209,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_file_extension.emplace_back(argv[i]); else- help("missing EXTENSIONS argument for option -O");+ usage("missing EXTENSIONS argument for option -O"); is_grouped = false; break; @@ -4071,7 +4270,7 @@ void options(int argc, const char **argv) else if (++i < argc) flag_file_type.emplace_back(argv[i]); else- help("missing TYPES argument for option -t");+ usage("missing TYPES argument for option -t"); is_grouped = false; break; @@ -4151,11 +4350,11 @@ void options(int argc, const char **argv) flag_min_depth = flag_max_depth; flag_max_depth = *arg - '0'; if (flag_min_depth > flag_max_depth)- help("invalid argument -", arg);+ usage("invalid argument -", arg); break; case '?':- help();+ help(arg[1] != '\0' ? arg + 1 : ++i < argc ? argv[i] : NULL); break; case '+':@@ -4167,7 +4366,7 @@ void options(int argc, const char **argv) break; default:- help("invalid option -", arg);+ usage("invalid option -", arg); } if (!is_grouped)@@ -4190,6 +4389,116 @@ void options(int argc, const char **argv) arg_files.emplace_back(arg); } }+}++// parse the command-line options and initialize+void init(int argc, const char **argv)+{+ // get home directory path to expand ~ in options with file arguments, using fopen_smart()++#ifdef OS_WIN+ home_dir = getenv("USERPROFILE");+#else+ home_dir = getenv("HOME");+#endif++ // load configuration file first before parsing all other options++ for (int i = 1; i < argc; ++i)+ {+ if (strcmp(argv[i], "--") == 0)+ break;++ if (strncmp(argv[i], "--config", 8) == 0)+ {+ if (flag_config != NULL)+ std::cerr << "ugrep: warning: multiple configurations specified, ignoring extra " << argv[i] << '\n';+ else if (argv[i][8] == '\0')+ flag_config = "";+ else if (argv[i][8] == '=')+ flag_config = argv[i] + 9;+ }+ else if (strncmp(argv[i], "---", 3) == 0)+ {+ if (flag_config != NULL)+ std::cerr << "ugrep: warning: multiple configurations specified, ignoring extra " << argv[i] << '\n';+ else+ flag_config = argv[i] + 3;+ }+ }++ if (flag_config != NULL)+ load_config();++ // apply the appropriate options when the program is named grep, egrep, fgrep, zgrep, zegrep, zfgrep++ const char *program = strrchr(argv[0], PATHSEPCHR);++ if (program == NULL)+ program = argv[0];+ else+ ++program;++ if (strcmp(program, "ug") == 0)+ {+ // the 'ug' command is equivalent to 'ugrep ---' to load custom configuration files, when no ---CONF is specified+ if (flag_config == NULL)+ load_config();+ }+ else if (strcmp(program, "grep") == 0)+ {+ // the 'grep' command is equivalent to 'ugrep -GY.'+ flag_basic_regexp = true;+ flag_hidden = true;+ flag_empty = true;+ }+ else if (strcmp(program, "egrep") == 0)+ {+ // the 'egrep' command is equivalent to 'ugrep -Y.'+ flag_hidden = true;+ flag_empty = true;+ }+ else if (strcmp(program, "fgrep") == 0)+ {+ // the 'fgrep' command is equivalent to 'ugrep -FY.'+ flag_fixed_strings = true;+ flag_hidden = true;+ flag_empty = true;+ }+ else if (strcmp(program, "zgrep") == 0)+ {+ // the 'zgrep' command is equivalent to 'ugrep -zGY.'+ flag_decompress = true;+ flag_basic_regexp = true;+ flag_hidden = true;+ flag_empty = true;+ }+ else if (strcmp(program, "zegrep") == 0)+ {+ // the 'zegrep' command is equivalent to 'ugrep -zY.'+ flag_decompress = true;+ flag_hidden = true;+ flag_empty = true;+ }+ else if (strcmp(program, "zfgrep") == 0)+ {+ // the 'zfgrep' command is equivalent to 'ugrep -zFY.'+ flag_decompress = true;+ flag_fixed_strings = true;+ flag_hidden = true;+ flag_empty = true;+ }++ // parse ugrep command-line options and arguments++ options(argc, argv);++ if (warnings > 0)+ {+ std::cerr << "Usage: ugrep [OPTIONS] [PATTERN] [-f FILE] [-e PATTERN] [FILE ...]\n";+ std::cerr << "Try 'ugrep --help [WHAT]' for more information\n";+ exit(EXIT_ERROR);+ } // -t list: list table of types and exit if (flag_file_type.size() == 1 && flag_file_type[0] == "list")@@ -4209,7 +4518,7 @@ void options(int argc, const char **argv) #ifndef HAVE_LIBZ // -z: but we don't have libz if (flag_decompress)- help("option -z is not available in this build configuration of ugrep");+ usage("option -z is not available in this build configuration of ugrep"); #endif // -P disables -G and -Z@@ -4219,13 +4528,21 @@ void options(int argc, const char **argv) flag_basic_regexp = false; flag_fuzzy = 0; #else- help("option -P is not available in this build configuration of ugrep");+ usage("option -P is not available in this build configuration of ugrep"); #endif } // check TTY info and set colors (warnings and errors may occur from here on) terminal(); + // --save-config and --save-config=FILE+ if (flag_save_config != NULL)+ {+ save_config();++ exit(EXIT_ERROR);+ }+ // --encoding: parse ENCODING value if (flag_encoding != NULL) {@@ -4244,7 +4561,7 @@ void options(int argc, const char **argv) msg.append(" '").append(encoding_table[i].format).append("',"); msg.pop_back(); - help(msg.c_str());+ usage(msg.c_str()); } // encoding is the file encoding used by all input files, if no BOM is present@@ -4261,7 +4578,7 @@ void options(int argc, const char **argv) else if (strcmp(flag_binary_files, "with-hex") == 0) flag_with_hex = true; else if (strcmp(flag_binary_files, "binary") != 0)- help("invalid argument --binary-files=TYPE, valid arguments are 'binary', 'without-match', 'text', 'hex', and 'with-hex'");+ usage("invalid argument --binary-files=TYPE, valid arguments are 'binary', 'without-match', 'text', 'hex', and 'with-hex'"); // --hexdump: normalize by assigning flags if (flag_hexdump != NULL)@@ -4270,7 +4587,7 @@ void options(int argc, const char **argv) { flag_hex_columns = 8 * (*flag_hexdump - '0'); if (flag_hex_columns == 0 || flag_hex_columns > MAX_HEX_COLUMNS)- help("invalid argument --hexdump=[1-8][b][c]");+ usage("invalid argument --hexdump=[1-8][b][c]"); } if (strchr(flag_hexdump, 'b') != NULL) flag_hex_hbr = flag_hex_cbr = false;@@ -4284,7 +4601,7 @@ void options(int argc, const char **argv) // --tabs: value should be 1, 2, 4, or 8 if (flag_tabs && flag_tabs != 1 && flag_tabs != 2 && flag_tabs != 4 && flag_tabs != 8)- help("invalid argument --tabs=NUM, valid arguments are 1, 2, 4, or 8");+ usage("invalid argument --tabs=NUM, valid arguments are 1, 2, 4, or 8"); // --match: same as specifying an empty "" pattern argument if (flag_match)@@ -4292,7 +4609,7 @@ void options(int argc, const char **argv) // if no regex pattern is specified and no -f file and not -Q, then exit with usage message if (arg_pattern == NULL && flag_regexp.empty() && flag_file.empty() && flag_query == 0)- help("no PATTERN specified: specify an empty \"\" pattern to match all input");+ usage("no PATTERN specified: specify an empty \"\" pattern to match all input"); // regex PATTERN should be a FILE argument when -Q or -e PATTERN is specified if (arg_pattern != NULL && (flag_query > 0 || !flag_regexp.empty()))@@ -4307,7 +4624,7 @@ void options(int argc, const char **argv) else if (strcmp(flag_devices, "read") == 0) flag_devices_action = Action::READ; else- help("invalid argument -D ACTION, valid arguments are 'skip' and 'read'");+ usage("invalid argument -D ACTION, valid arguments are 'skip' and 'read'"); // normalize -R (--dereference-recurse) option if (strcmp(flag_directories, "dereference-recurse") == 0)@@ -4324,7 +4641,7 @@ void options(int argc, const char **argv) else if (strcmp(flag_directories, "recurse") == 0) flag_directories_action = Action::RECURSE; else- help("invalid argument -d ACTION, valid arguments are 'skip', 'read', 'recurse', and 'dereference-recurse'");+ usage("invalid argument -d ACTION, valid arguments are 'skip', 'read', 'recurse', and 'dereference-recurse'"); // if no FILE specified and no -r or -R specified, when reading standard input from a TTY then enable -R if (!flag_stdin && arg_files.empty() && flag_directories_action != Action::RECURSE && isatty(STDIN_FILENO))@@ -4338,7 +4655,7 @@ void options(int argc, const char **argv) flag_stdin = true; // check FILE arguments, warn about non-existing FILE- std::vector<const char*>::iterator file = arg_files.begin();+ auto file = arg_files.begin(); while (file != arg_files.end()) { #ifdef OS_WIN@@ -4492,9 +4809,7 @@ void options(int argc, const char **argv) { FILE *file = NULL; - if (from == "-")- file = stdin;- else if (fopen_s(&file, from.c_str(), "r") != 0)+ if (fopen_smart(&file, from.c_str(), "r") != 0) error("cannot read", from.c_str()); extend(file, flag_exclude, flag_exclude_dir, flag_not_exclude, flag_not_exclude_dir);@@ -4511,9 +4826,7 @@ void options(int argc, const char **argv) { FILE *file = NULL; - if (from == "-")- file = stdin;- else if (fopen_s(&file, from.c_str(), "r") != 0)+ if (fopen_smart(&file, from.c_str(), "r") != 0) error("cannot read", from.c_str()); extend(file, flag_include, flag_include_dir, flag_not_include, flag_not_include_dir);@@ -4560,7 +4873,7 @@ void options(int argc, const char **argv) msg.append(" '").append(type_table[i].type).append("',"); msg.append(" and 'list' to show a detailed list of file types"); - help(msg.c_str());+ usage(msg.c_str()); } std::string extensions(type_table[i].extensions);@@ -4673,20 +4986,23 @@ void options(int argc, const char **argv) // --filter-magic-label: append pattern to magic_labels, parenthesized to ensure capture indexing for (auto& label : flag_filter_magic_label) {- size_t sep = label.find(':');-- if (sep != std::string::npos && sep > 0 && sep + 1 < label.size())+ if (!label.empty()) {- if (!label.empty() && magic_regex.size() > 1)- magic_regex.append(")|(");- magic_regex.append(label.substr(sep + 1));+ size_t sep = label.find(':'); - // truncate so we end up with a list of labels without patterns- label.resize(sep);- }- else- {- abort("option --filter-magic-label: invalid LABEL:MAGIC argument ", label);+ if (sep != std::string::npos && sep > 0 && sep + 1 < label.size())+ {+ if (!label.empty() && magic_regex.size() > 1)+ magic_regex.append(")|(");+ magic_regex.append(label.substr(sep + 1));++ // truncate so we end up with a list of labels without patterns+ label.resize(sep);+ }+ else+ {+ abort("option --filter-magic-label: invalid LABEL:MAGIC argument ", label);+ } } } @@ -4855,7 +5171,7 @@ void terminal() } else if (strcmp(flag_apply_color, "always") != 0) {- help("invalid argument --color=WHEN, valid arguments are 'never', 'always', and 'auto'");+ usage("invalid argument --color=WHEN, valid arguments are 'never', 'always', and 'auto'"); } if (flag_apply_color != NULL)@@ -4885,7 +5201,7 @@ void terminal() set_color(grep_colors, "bn", color_bn); // byte offset set_color(grep_colors, "se", color_se); // separator - // parse --colors+ // 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@@ -5107,7 +5423,7 @@ void ugrep() else if (strcmp(flag_sort, "created") == 0 || strcmp(flag_sort, "rcreated") == 0) flag_sort_key = Sort::CREATED; else- help("invalid argument --sort=KEY, valid arguments are 'name', 'best', 'size', 'used', 'changed', 'created', 'rname', 'rbest', 'rsize', 'rused', 'rchanged', and 'rcreated'");+ usage("invalid argument --sort=KEY, valid arguments are 'name', 'best', 'size', 'used', 'changed', 'created', 'rname', 'rbest', 'rsize', 'rused', 'rchanged', and 'rcreated'"); } // -x: enable -Y@@ -5136,20 +5452,23 @@ void ugrep() // pattern ".*\n?|" could be used throughout without flag_empty = true, but this garbles output for -o, -H, -n, etc. if (flag_line_regexp) {+ // -x: with an empty pattern means we're matching empty lines regex.append("^$|"); } else if (flag_hex) {+ // we're matching everything including \n regex.append(".*\n?|"); - // we're matching everything+ // indicate that we're matching everything flag_match = true; } else {- regex.append(".*|");+ // we're matching lines+ regex.append("^.*$|"); - // we're matching everything+ // indicate that we're matching everything flag_match = true; } @@ -5335,9 +5654,7 @@ void ugrep() { FILE *file = NULL; - if (filename == "-")- file = stdin;- else if (fopen_s(&file, filename.c_str(), "r") != 0)+ if (fopen_smart(&file, filename.c_str(), "r") != 0) file = NULL; if (file == NULL)@@ -5348,10 +5665,7 @@ void ugrep() if (env_grep_path != NULL) {- std::string path_file(env_grep_path);- path_file.append(PATHSEPSTR).append(filename);-- if (fopen_s(&file, path_file.c_str(), "r") != 0)+ if (fopen_smart(&file, std::string(env_grep_path).append(PATHSEPSTR).append(filename).c_str(), "r") != 0) file = NULL; free(env_grep_path);@@ -5361,10 +5675,7 @@ void ugrep() #ifdef GREP_PATH if (file == NULL) {- std::string path_file(GREP_PATH);- path_file.append(PATHSEPSTR).append(filename);-- if (fopen_s(&file, path_file.c_str(), "r") != 0)+ if (fopen_smart(&file, std::string(GREP_PATH).append(PATHSEPSTR).append(filename).c_str(), "r") != 0) file = NULL; } #endif@@ -6383,7 +6694,7 @@ void Grep::recurse(size_t level, const char *pathname) // -Z and --sort=best: presearch the selected files to determine edit distance cost if (flag_fuzzy > 0 && flag_sort_key == Sort::BEST) {- std::vector<Entry>::iterator entry = content.begin();+ auto entry = content.begin(); while (entry != content.end()) { entry->cost = cost(entry->pathname.c_str());@@ -9012,7 +9323,7 @@ size_t strtonum(const char *string, const char *message) char *rest = NULL; size_t size = static_cast<size_t>(strtoull(string, &rest, 10)); if (rest == NULL || *rest != '\0')- help(message, string);+ usage(message, string); return size; } @@ -9021,7 +9332,7 @@ size_t strtopos(const char *string, const char *message) { size_t size = strtonum(string, message); if (size == 0)- help(message, string);+ usage(message, string); return size; } @@ -9040,7 +9351,7 @@ void strtopos2(const char *string, size_t& pos1, size_t& pos2, const char *messa else pos2 = 0; if (rest == NULL || *rest != '\0' || (pos2 > 0 && pos1 > pos2))- help(message, string);+ usage(message, string); } // convert unsigned decimal MAX fuzzy with optional prefix '+', '-', or '~' to positive size_t@@ -9068,7 +9379,7 @@ size_t strtofuzzy(const char *string, const char *message) default: max = static_cast<size_t>(strtoull(string, &rest, 10)); if (max == 0 || max > 255 || rest == NULL || *rest != '\0')- help(message, string);+ usage(message, string); string = rest; } }@@ -9076,20 +9387,19 @@ size_t strtofuzzy(const char *string, const char *message) } // display diagnostic message and exit-void help(const char *message, const char *arg, const char *valid)+void usage(const char *message, const char *arg, const char *valid) { std::cerr << "ugrep: " << message << (arg != NULL ? arg : ""); if (valid != NULL) std::cerr << ", did you mean " << valid << "?";- std::cerr << "\nUsage: ugrep [OPTIONS] [PATTERN] [-f FILE] [-e PATTERN] [FILE ...]\n";- std::cerr << "Try 'ugrep --help' for more information.\n";- exit(EXIT_ERROR);+ std::cerr << std::endl;+ ++warnings; } // display usage/help information and exit-void help()+void help(std::ostream& out) {- std::cout <<+ out << "Usage: ugrep [OPTIONS] [PATTERN] [-f FILE] [-e PATTERN] [FILE ...]\n\n\ -A NUM, --after-context=NUM\n\ Print NUM lines of trailing context after matching lines. Places\n\@@ -9150,8 +9460,13 @@ void help() bright. A foreground and a background color may be combined with\n\ font properties `n' (normal), `f' (faint), `h' (highlight), `i'\n\ (invert), `u' (underline). Selectively overrides GREP_COLORS.\n\- --no-confirm\n\- Do not confirm actions in -Q query mode. The default is confirm.\n\+ --config[=FILE], ---[FILE]\n\+ Use configuration FILE. The default FILE is `.ugrep'. The working\n\+ directory is checked first for FILE, then the home directory. The\n\+ options specified in the configuration FILE are parsed first,\n\+ followed by the remaining options on the command line.\n\+ --confirm\n\+ Confirm actions in -Q query mode. The default is confirm.\n\ --cpp\n\ Output file matches in C++. See also options --format and -u.\n\ --csv\n\@@ -9190,8 +9505,8 @@ void help() --encoding=ENCODING\n\ The encoding format of the input, where ENCODING can be:"; for (int i = 0; encoding_table[i].format != NULL; ++i)- std::cout << (i == 0 ? "" : ",") << (i % 4 ? " " : "\n ") << "`" << encoding_table[i].format << "'";- std::cout << ".\n\+ out << (i == 0 ? "" : ",") << (i % 4 ? " " : "\n ") << "`" << encoding_table[i].format << "'";+ out << ".\n\ --exclude=GLOB\n\ Skip files whose name matches GLOB using wildcard matching, same as\n\ -g ^GLOB. GLOB can use **, *, ?, and [...] as wildcards, and \\ to\n\@@ -9220,12 +9535,12 @@ void help() Exclude file systems specified by MOUNTS from recursive searches,\n\ MOUNTS is a comma-separated list of mount points or pathnames of\n\ directories on file systems. Note that --exclude-fs mounts take\n\- priority over --include-fs mounts. This option may be repeated.\n";+ priority over --include-fs mounts. This option may be repeated.\n" #ifndef HAVE_STATVFS- std::cout << "\- This option is not available in this build configuration of ugrep.\n";+ "\+ This option is not available in this build configuration of ugrep.\n" #endif- std::cout << "\+ "\ -F, --fixed-strings\n\ Interpret pattern as a set of fixed strings, separated by newlines,\n\ any of which is to be matched. This makes ugrep behave as fgrep.\n\@@ -9236,14 +9551,14 @@ void help() is significant. Empty lines in FILE are ignored. If FILE does not\n\ exist, the GREP_PATH environment variable is used as path to FILE.\n" #ifdef GREP_PATH-"\+ "\ If that fails, looks for FILE in " GREP_PATH ".\n" #endif-"\+ "\ When FILE is a `-', standard input is read. Empty files contain no\n\- patterns; thus nothing is matched. This option may be repeated.\n";+ patterns; thus nothing is matched. This option may be repeated.\n" #ifndef OS_WIN- std::cout << "\+ "\ --filter=COMMANDS\n\ Filter files through the specified COMMANDS first before searching.\n\ COMMANDS is a comma-separated list of `exts:command [option ...]',\n\@@ -9262,9 +9577,9 @@ void help() MAGIC regex pattern. Only files that have no filename extension\n\ are labeled, unless +LABEL is specified. When LABEL matches an\n\ extension specified in --filter=COMMANDS, the corresponding command\n\- is invoked. This option may be repeated.\n";+ is invoked. This option may be repeated.\n" #endif- std::cout << "\+ "\ --format=FORMAT\n\ Output FORMAT-formatted matches. See `man ugrep' section FORMAT\n\ for the `%' fields.\n\@@ -9295,20 +9610,20 @@ void help() --heading, -+\n\ Group matches per file. Adds a heading and a line break between\n\ results from different files.\n\- --help, -?\n\- Print a help message.\n\+ --help [WHAT], -? [WHAT]\n\+ Display a help message, specifically on WHAT when specified.\n\ --hexdump=[1-8][b][c][h]\n\ Output matches in 1 to 8 columns of 8 hexadecimal octets. The\n\ default is 2 columns or 16 octets per line. Option `b' removes all\n\ space breaks, `c' hides the character column, and `h' removes the\n\ hex spacing only. Enables -X if -W or -X is not specified.\n\ --hidden, -.\n\- Search ";+ Search " #ifdef OS_WIN- std::cout << "Windows system and ";+ "Windows system and " #endif- std::cout << "hidden files and directories.\n\- -I\n\+ "hidden files and directories.\n\+ -I, --ignore-binary\n\ Ignore matches in binary files. This option is equivalent to the\n\ --binary-files=without-match option.\n\ -i, --ignore-case\n\@@ -9318,8 +9633,8 @@ void help() Ignore files and directories matching the globs in each FILE that\n\ is encountered in recursive searches. The default FILE is\n\ `" DEFAULT_IGNORE_FILE "'. Matching files and directories located in the\n\- directory tree rooted at a FILE's location are ignored by\n\- temporarily overriding the --exclude and --exclude-dir globs.\n\+ directory of a FILE's location and in directories below are ignored\n\+ by temporarily overriding the --exclude and --exclude-dir globs.\n\ Files and directories that are explicitly specified as command line\n\ arguments are never ignored. This option may be repeated.\n\ --include=GLOB\n\@@ -9352,12 +9667,12 @@ void help() pathnames of directories on file systems. --include-fs=. restricts\n\ recursive searches to the file system of the working directory\n\ only. Note that --exclude-fs mounts take priority over\n\- --include-fs mounts. This option may be repeated.\n";+ --include-fs mounts. This option may be repeated.\n" #ifndef HAVE_STATVFS- std::cout << "\- This option is not available in this build configuration of ugrep.\n";+ "\+ This option is not available in this build configuration of ugrep.\n" #endif- std::cout << "\+ "\ -J NUM, --jobs=NUM\n\ Specifies the number of threads spawned to search files. By\n\ default an optimum number of threads is spawned to search files\n\@@ -9408,10 +9723,10 @@ void help() Restrict the number of files matched to NUM. Note that --sort or\n\ -J1 may be specified to produce replicable results. If --sort is\n\ specified, the number of threads spawned is limited to NUM.\n\- --[no-]mmap[=MAX]\n\- Do (not) use memory maps to search files. By default, memory maps\n\- are used under certain conditions to improve performance. When MAX\n\- is specified, use up to MAX mmap memory per thread.\n\+ --mmap[=MAX]\n\+ Use memory maps to search files. By default, memory maps are used\n\+ 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\@@ -9444,16 +9759,16 @@ void help() displaying the match. The line number counter is reset for each\n\ file processed.\n\ -P, --perl-regexp\n\- Interpret PATTERN as a Perl regular expression";+ Interpret PATTERN as a Perl regular expression" #if defined(HAVE_PCRE2)- std::cout << " using PCRE2.\n";+ " using PCRE2.\n" #elif defined(HAVE_BOOST_REGEX)- std::cout << " using Boost.Regex.\n";+ " using Boost.Regex.\n" #else- std::cout << ".\n\- This option is not available in this build configuration of ugrep.\n";+ ".\n\+ This option is not available in this build configuration of ugrep.\n" #endif- std::cout << "\+ "\ -p, --no-dereference\n\ If -R or -r is specified, no symbolic links are followed, even when\n\ they are specified on the command line.\n\@@ -9477,7 +9792,7 @@ void help() GREP_EDIT is not defined. Enables --heading.\n\ -q, --quiet, --silent\n\ Quiet mode: suppress all output. ugrep will only search until a\n\- match has been found, making searches potentially less expensive.\n\+ match has been found.\n\ -R, --dereference-recursive\n\ Recursively read all files under each directory. Follow all\n\ symbolic links, unlike -r. When -J1 is specified, files are\n\@@ -9488,14 +9803,15 @@ void help() Recursively read all files under each directory, following symbolic\n\ links only if they are on the command line. When -J1 is specified,\n\ files are searched in the same order as specified.\n\- --range=FIRST[,LAST]\n\- Start searching at line FIRST, stop at line LAST when specified.\n\ -S, --dereference\n\ If -r is specified, all symbolic links are followed, like -R. The\n\ default is not to follow symbolic links.\n\ -s, --no-messages\n\ Silent mode: nonexistent and unreadable files are ignored, i.e.\n\ their error messages are suppressed.\n\+ --save-config[=FILE]\n\+ Save configuration FILE. By default `.ugrep' is saved. If FILE is\n\+ a `-', write the configuration to standard output.\n\ --separator[=SEP]\n\ Use SEP as field separator between file name, line number, column\n\ number, byte offset, and the matched line. The default is a colon\n\@@ -9528,31 +9844,31 @@ void help() option may be repeated. The possible file types can be (where\n\ -tlist displays a detailed list):"; for (int i = 0; type_table[i].type != NULL; ++i)- std::cout << (i == 0 ? "" : ",") << (i % 7 ? " " : "\n ") << "`" << type_table[i].type << "'";- std::cout << ".\n\+ out << (i == 0 ? "" : ",") << (i % 7 ? " " : "\n ") << "`" << type_table[i].type << "'";+ out << ".\n\ --tabs[=NUM]\n\ Set the tab size to NUM to expand tabs for option -k. The value of\n\ NUM may be 1, 2, 4, or 8. The default tab size is 8.\n\ --tag[=TAG[,END]]\n\ Disables colors to mark up matches with TAG. END marks the end of\n\ a match if specified, otherwise TAG. The default is `___'.\n\- -U, --binary\n";+ -U, --binary\n" #ifdef OS_WIN- std::cout << "\+ "\ Opens files in binary mode (mode specific to Windows) and disables\n\ Unicode matching for binary file matching, forcing PATTERN to match\n\ bytes, not Unicode characters. For example, -U '\\xa3' matches\n\ byte A3 (hex) instead of the Unicode code point U+00A3 represented\n\ by the two-byte UTF-8 sequence C2 A3. Note that binary files\n\- may appear truncated when searched without this option.\n";+ may appear truncated when searched without this option.\n" #else- std::cout << "\+ "\ Disables Unicode matching for binary file matching, forcing PATTERN\n\ to match bytes, not Unicode characters. For example, -U '\\xa3'\n\ matches byte A3 (hex) instead of the Unicode code point U+00A3\n\- represented by the two-byte UTF-8 sequence C2 A3.\n";+ represented by the two-byte UTF-8 sequence C2 A3.\n" #endif- std::cout << "\+ "\ -u, --ungroup\n\ Do not group multiple pattern matches on the same matched line.\n\ Output the matched line again for each additional pattern match,\n\@@ -9606,38 +9922,120 @@ void help() matching pathnames of files in archives are output in braces. If\n\ -g, -O, -M, or -t is specified, searches files within archives\n\ whose name matches globs, matches file name extensions, matches\n\- file signature magic bytes, or matches file types, respectively.\n";+ file signature magic bytes, or matches file types, respectively.\n" #ifndef HAVE_LIBZ- std::cout << "\- This option is not available in this build configuration of ugrep.\n";+ "\+ This option is not available in this build configuration of ugrep.\n" #else- std::cout << "\- Supported compression formats: gzip (.gz), compress (.Z), zip";+ "\+ Supported compression formats: gzip (.gz), compress (.Z), zip" #ifdef HAVE_LIBBZ2- std::cout << ",\n\- bzip2 (requires suffix .bz, .bz2, .bzip2, .tbz, .tbz2, .tb2, .tz2)";+ ",\n\+ bzip2 (requires suffix .bz, .bz2, .bzip2, .tbz, .tbz2, .tb2, .tz2)" #endif #ifdef HAVE_LIBLZMA- std::cout << ",\n\- lzma and xz (requires suffix .lzma, .tlz, .xz, .txz)";+ ",\n\+ lzma and xz (requires suffix .lzma, .tlz, .xz, .txz)" #endif- std::cout << ".\n";+ ".\n" #endif- std::cout << "\+ "\ -0, --null\n\ Prints a zero-byte (NUL) after the file name. This option can be\n\ used with commands such as `find -print0' and `xargs -0' to process\n\ arbitrary file names.\n\ \n\- The ugrep utility exits with one of the following values:\n\+ Long options may start with `--no-' to disable, when applicable.\n\ \n\+ The ugrep utility exits with one of the following values:\n\ 0 One or more lines were selected.\n\ 1 No lines were selected.\n\ >1 An error occurred.\n\ \n\ If -q or --quiet or --silent is used and a line is selected, the exit\n\- status is 0 even if an error occurred.\n\-" << std::endl;+ status is 0 even if an error occurred.\n\n";+}++// display helpful information for WHAT, if specified, and exit+void help(const char *what)+{+ if (what == NULL)+ {+ help(std::cout);+ }+ else+ {+ if (*what == '=')+ ++what;++ if (strncmp(what, "--no", 4) == 0)+ what += 4;++ if (*what == '\0')+ {+ help(std::cout);+ }+ else+ {+ std::stringstream text;+ help(text);+ const std::string& str = text.str();++ int found = 0;++ for (int pass = 0; pass < 2; ++pass)+ {+ size_t pos = 0;++ while (true)+ {+ size_t end = str.find("\n -", pos + 1);++ if (end == std::string::npos)+ end = str.find("\n\n", pos + 1);++ if (end == std::string::npos)+ break;++ size_t nl = str.find('\n', pos + 1);++ // roughly find a case-independent match of WHAT+ for (size_t i = pos + 5; i < (pass == 0 ? nl : end); ++i)+ {+ size_t j = 0;++ for (j = 0; what[j] != '\0'; ++j)+ if (((what[j] ^ str.at(i + j)) & ~0x20) != 0)+ break;++ if (what[j] == '\0')+ {+ if (pass == 0 ? i < nl: i > nl)+ {+ if (found == 0 && pass == 0)+ std::cout << "\nOptions and arguments:\n";+ else if (found == 1 && pass == 1)+ std::cout << "\n\nOther options:\n";+ else if (found == 0)+ std::cout << "\nNo matching option, other relevant options:\n";++ std::cout << str.substr(pos, end - pos);+ found = pass + 1;+ }+ break;+ }+ }++ pos = end;+ }+ }++ if (found == 0)+ std::cout << "ugrep --help: nothing appropriate for " << what;++ std::cout << "\n\n";+ }+ } exit(EXIT_ERROR); }@@ -9650,9 +10048,9 @@ void version() #endif std::cout << "ugrep " UGREP_VERSION " " PLATFORM << #if defined(HAVE_AVX512BW)- (reflex::Matcher::have_HW_AVX512BW() ? " +avx512" : (reflex::Matcher::have_HW_AVX() ? " +avx" : reflex::Matcher::have_HW_SSE2() ? " +sse2" : " (-avx512)")) <<-#elif defined(HAVE_AVX)- (reflex::Matcher::have_HW_AVX() ? " +avx" : reflex::Matcher::have_HW_SSE2() ? " +sse2" : " (-avx)") <<+ (reflex::Matcher::have_HW_AVX512BW() ? " +avx512" : (reflex::Matcher::have_HW_AVX2() ? " +avx2" : reflex::Matcher::have_HW_SSE2() ? " +sse2" : " (-avx512)")) <<+#elif defined(HAVE_AVX2)+ (reflex::Matcher::have_HW_AVX2() ? " +avx2" : reflex::Matcher::have_HW_SSE2() ? " +sse2" : " (-avx2)") << #elif defined(HAVE_SSE2) (reflex::Matcher::have_HW_SSE2() ? " +sse2" : " (-sse2)") << #elif defined(HAVE_NEON)
@@ -156,6 +156,7 @@ inline int fopen_s(FILE **file, const char *filename, const char *mode) #include <algorithm> #include <atomic> #include <map>+#include <set> #include <string> #include <vector> @@ -169,7 +170,6 @@ enum class Sort { NA, NAME, BEST, SIZE, USED, CHANGED, CREATED }; enum class Action { SKIP, READ, RECURSE }; // ugrep command-line options and internal flags-extern bool flag_no_confirm; extern bool flag_no_header; extern bool flag_no_messages; extern bool flag_match;@@ -217,6 +217,7 @@ extern bool flag_all_threads; extern bool flag_heading; extern bool flag_pretty; extern bool flag_hidden;+extern bool flag_confirm; extern bool flag_hex_hbr; extern bool flag_hex_cbr; extern bool flag_hex_chr;@@ -262,6 +263,10 @@ extern const char *flag_label; extern const char *flag_separator; extern const char *flag_group_separator; extern const char *flag_binary_files;+extern const char *flag_config;+extern const char *flag_save_config;+extern std::string flag_config_file;+extern std::set<std::string> flag_config_options; extern std::vector<std::string> flag_regexp; extern std::vector<std::string> flag_neg_regexp; extern std::vector<std::string> flag_file;
@@ -118,7 +118,7 @@ Configuration Properties General: Additional Include Directories: $(ProjectDir)\include;$(ProjectDir)\..\pcre2-10.34\src;$(ProjectDir)\..\zlib-1.2.11;$(ProjectDir)\..\bzip2-1.0.5;$(ProjectDir)\..\api Preprocessor: - Preprocessor Definitions: WIN32;NDEBUG;_CONSOLE;WITH_NO_INDENT;HAVE_AVX;HAVE_PCRE2;PCRE2_STATIC;HAVE_LIBZ;HAVE_LIBBZ2;HAVE_LIBLZMA;WITH_COLOR;ZLIB_WINAPI;NO_GZCOMPRESS;LZMA_API_STATIC;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS+ Preprocessor Definitions: WIN32;NDEBUG;_CONSOLE;WITH_NO_INDENT;HAVE_AVX2;HAVE_PCRE2;PCRE2_STATIC;HAVE_LIBZ;HAVE_LIBBZ2;HAVE_LIBLZMA;WITH_COLOR;ZLIB_WINAPI;NO_GZCOMPRESS;LZMA_API_STATIC;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS Code Generation: Runtime Library: Multi-threaded (/MT)@@ -188,7 +188,7 @@ Configuration Properties General: Additional Include Directories: $(ProjectDir)\include;$(ProjectDir)\..\boost_1_72_0;$(ProjectDir)\..\zlib-1.2.11;$(ProjectDir)\..\bzip2-1.0.5;$(ProjectDir)\..\api Preprocessor: - Preprocessor Definitions: WIN32;NDEBUG;_CONSOLE;WITH_NO_INDENT;HAVE_AVX;HAVE_BOOST_REGEX;HAVE_LIBZ;HAVE_LIBBZ2;HAVE_LIBLZMA;WITH_COLOR;ZLIB_WINAPI;NO_GZCOMPRESS;LZMA_API_STATIC;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS+ Preprocessor Definitions: WIN32;NDEBUG;_CONSOLE;WITH_NO_INDENT;HAVE_AVX2;HAVE_BOOST_REGEX;HAVE_LIBZ;HAVE_LIBBZ2;HAVE_LIBLZMA;WITH_COLOR;ZLIB_WINAPI;NO_GZCOMPRESS;LZMA_API_STATIC;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS Code Generation: Runtime Library: Multi-threaded (/MT)