211220.3 · cc8668306692ed28dae7007ed24bd4f4df6addae
released 3.4.0 new options --files and --lines for --bool searching
reading declarations
@@ -1,6 +1,6 @@ [![build status][travis-image]][travis-url] [![Language grade: C/C++][lgtm-image]][lgtm-url] [![license][bsd-3-image]][bsd-3-url] -**ugrep v3.3 is now available: more features & even faster than before**+**ugrep v3.4 is now available: more features & even faster than before** Search for anything in everything... ultra fast @@ -30,7 +30,7 @@ Search for anything in everything... ultra fast ugrep -Z PATTERN ... ugrep -Z3 PATTTERN ... -- Search with Google-like [Boolean search patterns](#bool) with option `--bool` patterns with `AND` (or just space), `OR` (or a bar `|`), `NOT` (or a dash `-`), using quotes to match exactly, and grouping with `( )`; or with options `-e` (as an "or"), `--and`, `--andnot`, and `--not` regex patterns+- Search with Google-like [Boolean query patterns](#bool) using `--bool` patterns with `AND` (or just space), `OR` (or a bar `|`), `NOT` (or a dash `-`), using quotes to match exactly, and grouping with `( )`; or with options `-e` (as an "or"), `--and`, `--andnot`, and `--not` regex patterns ugrep --bool 'PATT1 PATT2 PATT3' ... ugrep -e PATT1 --and PATT2 --and PATT3 ... ugrep --bool 'PATT1|PATT2 PATT3' ... ugrep -e PATT1 -e PATT2 --and PATT3 ...@@ -38,9 +38,12 @@ Search for anything in everything... ultra fast ugrep --bool 'PATT1 -(PATT2|PATT3)'... ugrep -e PATT1 --andnot PATT2 --andnot PATT3 ... ugrep --bool '"PATT1" "PATT2"' ... ugrep -e '\QPATT1\E' --and '\QPATT2\E' ... + Boolean query conditions apply to lines by default (grep is a line matching tool!) Specify `--files --bool` to apply the Boolean query to files as a whole: a file matches if all Boolean conditions are satisfied by matching patterns anywhere in the file.+ - Fzf-like search with regex (or fixed strings with `-F`), fuzzy matching with up to 4 extra characters with `-Z+4`, and words only with `-w`, press TAB and ALT-y to view a file, SHIFT-TAB and Alt-l to go back to view the list of matching files ordered by best match ugrep -Q1 --bool -l -w -Z+4 --sort=best+ ugrep -Q1 --files --bool -l -w -Z+4 --sort=best - Search the contents of [archives](#archives) (cpio, jar, tar, pax, zip) and [compressed files](#archives) (zip, gz, Z, bz, bz2, lzma, xz, lz4, zstd) @@ -51,6 +54,7 @@ Search for anything in everything... ultra fast ugrep --filter='pdf:pdftotext % -' PATTERN ... ugrep --filter='odt,doc,docx,rtf,xls,xlsx,ppt,pptx:soffice --headless --cat %' PATTERN ... ugrep --filter='pem:openssl x509 -text,cer,crt,der:openssl x509 -text -inform der' PATTERN ...+ ugrep --filter='latin1:iconv -f LATIN1 -t UTF-8' PATTERN ... - Search [binary files](#binary) and display hexdumps with binary pattern matches (Unicode text or raw byte patterns) @@ -131,7 +135,7 @@ Table of contents - [Configuration files](#config) - [Interactive search with -Q](#query) - [Recursively list matching files with -l, -R, -r, --depth, -g, -O, and -t](#recursion)- - [Boolean search patterns with --bool (-%), --and, --not](#bool)+ - [Boolean query patterns with --bool (-%), --and, --not](#bool) - [Search this but not that with -v, -e, -N, -f, -L, -w, -x](#not) - [Search non-Unicode files with --encoding](#encoding) - [Matching multiple lines of text](#multiline)@@ -1308,10 +1312,10 @@ To recursively list all shell scripts based on extensions only with `-tshell`: <a name="bool"/> -### Boolean search patterns with --bool (-%), --and, --not+### Boolean query patterns with --bool (-%), --and, --not --bool, -%- Specifies Boolean search patterns. A Boolean search pattern is+ Specifies Boolean query patterns. A Boolean query pattern is composed of `AND', `OR', `NOT' operators and grouping with `(' `)'. Spacing between subpatterns is the same as `AND', `|' is the same as `OR', and a `-' is the same as `NOT'. The `OR' operator binds@@ -1325,12 +1329,24 @@ To recursively list all shell scripts based on extensions only with `-tshell`: lines with `A' and also either `AND' or `OR'. Parenthesis are used for grouping. For example, --bool '(A B)|C' matches lines with `A' and `B', or lines with `C'. Note that all subpatterns in a Boolean- search pattern are regular expressions, unless option -F is used.+ query pattern are regular expressions, unless option -F is used. Options -E, -F, -G, -P, and -Z can be combined with --bool to match subpatterns as strings or regular expressions (-E is the default.) This option does not apply to -f FILE patterns. Option --stats displays the search patterns applied. See also options --and,- --andnot, and --not.+ --andnot, --not, --files, and --lines.+ --files+ Apply Boolean queries to match files, the opposite of --lines. A+ file matches if all Boolean conditions are satisfied by the lines+ matched in the file. For example, --files -e A --and -e B -e C+ --andnot -e D matches a file if some lines match `A' and some lines+ match (`B' or `C') and no line in the file matches `D'. May also+ be specified as --files --bool 'A B|C -D'. Option -v cannot be+ specified with --files. See also options --and, --andnot, --not,+ --bool and --lines.+ --lines+ Apply Boolean queries to match lines, the opposite of --files.+ This is the default Boolean query mode to match specific lines. --and [[-e] PATTERN] ... -e PATTERN Specify additional patterns to match. Patterns must be specified with -e. Each -e PATTERN following this option is considered an@@ -1354,8 +1370,8 @@ To recursively list all shell scripts based on extensions only with `-tshell`: Note that the `--and`, `--not`, and `--andnot` options require `-e PATTERN`. -The `--bool` option makes all patterns Boolean expressions supporting the-following operations:+The `--bool` option makes all patterns Boolean-based, supporting the following+logical operations: operator | alternative | result -------- | ----------- | -------@@ -1374,7 +1390,7 @@ operator | alternative | result - `-` and `NOT` are the same and take precedence over `OR`, which means that `-x|y` == `(-x)|y` for example. -The `--stats` option displays the Boolean search query in human-readable form+The `--stats` option displays the Boolean queries in human-readable form converted to CNF (Conjunctive Normal Form), after the search is completed. To show the CNF without a search, read from standard input terminated by an EOF, like `echo | ugrep --bool '...' --stats`.@@ -1399,6 +1415,12 @@ and ALT-l to go back to the list of matching files: ugrep -Q1 --bool -l -w -F -Z+4 --sort=best +To recursively find all files containing both `hot` and `dog` anywhere in the+file with option `--files`:++ ugrep --files --bool 'hot dog'+ ugrep --files -e hot --and dog+ To find lines containing both `hot` and `dog` in `myfile.txt`: ugrep --bool 'hot dog' myfile.txt@@ -1497,6 +1519,9 @@ same line, like XOR: -f FILE patterns to allow -f FILE patterns to narrow or widen the scope of the PATTERN search. +See also [Boolean query patterns with --bool (-%), --and, --not](#bool) for+more powerful Boolean query options than the traditional GNU/BSD grep options.+ To display lines in file `myfile.sh` but not lines matching `^[ \t]*#`: ugrep -v '^[ \t]*#' myfile.sh@@ -3569,100 +3594,101 @@ in markdown: matches lines with (`A' or `B') and (`C' or `D'). Note that multiple -e PATTERN are alternations that bind more tightly together than --and. Option --stats displays the search pat-- terns applied. See also options --not, --andnot, and --bool.+ terns applied. See also options --not, --andnot, --bool,+ --files, and --lines. --andnot [[-e] PATTERN] ...- Combines --and --not. See also options --and, --not, and+ Combines --and --not. See also options --and, --not, and --bool. -B NUM, --before-context=NUM- Print NUM lines of leading context before matching lines.+ Print NUM lines of leading context before matching lines. Places a --group-separator between contiguous groups of matches. See also options -A, -C, and -y. -b, --byte-offset- The offset in bytes of a matched line is displayed in front of- the respective matched line. If -u is specified, displays the- offset for each pattern matched on the same line. Byte offsets- are exact for ASCII, UTF-8, and raw binary input. Otherwise,+ The offset in bytes of a matched line is displayed in front of+ the respective matched line. If -u is specified, displays the+ offset for each pattern matched on the same line. Byte offsets+ are exact for ASCII, UTF-8, and raw binary input. Otherwise, the byte offset in the UTF-8 normalized input is displayed. --binary-files=TYPE- Controls searching and reporting pattern matches in binary- files. TYPE can be `binary', `without-match`, `text`, `hex`,- and `with-hex'. The default is `binary' to search binary files- and to report a match without displaying the match. `with-- out-match' ignores binary matches. `text' treats all binary- files as text, which might output binary garbage to the termi-- nal, which can have problematic consequences if the terminal- driver interprets some of it as commands. `hex' reports all- matches in hexadecimal. `with-hex' only reports binary matches- in hexadecimal, leaving text matches alone. A match is consid-- ered binary when matching a zero byte or invalid UTF. Short+ Controls searching and reporting pattern matches in binary+ files. TYPE can be `binary', `without-match`, `text`, `hex`,+ and `with-hex'. The default is `binary' to search binary files+ and to report a match without displaying the match. `with-+ out-match' ignores binary matches. `text' treats all binary+ files as text, which might output binary garbage to the termi-+ nal, which can have problematic consequences if the terminal+ driver interprets some of it as commands. `hex' reports all+ matches in hexadecimal. `with-hex' only reports binary matches+ in hexadecimal, leaving text matches alone. A match is consid-+ ered binary when matching a zero byte or invalid UTF. Short options are -a, -I, -U, -W, and -X. --bool, -%- Specifies Boolean search patterns. A Boolean search pattern is- composed of `AND', `OR', `NOT' operators and grouping with `('- `)'. Spacing between subpatterns is the same as `AND', `|' is- the same as `OR', and a `-' is the same as `NOT'. The `OR'- operator binds more tightly than `AND'. For example, --bool- 'A|B C|D' matches lines with (`A' or `B') and (`C' or `D'),- --bool 'A -B' matches lines with `A' and not `B'. Operators- `AND', `OR', `NOT' require proper spacing. For example, --bool- 'A OR B AND C OR D' matches lines with (`A' or `B') and (`C' or- `D'), --bool 'A AND NOT B' matches lines with `A' without `B'.- Quoted subpatterns are matched literally as strings. For exam-- ple, --bool 'A "AND"|"OR"' matches lines with `A' and also- either `AND' or `OR'. Parenthesis are used for grouping. For- example, --bool '(A B)|C' matches lines with `A' and `B', or- lines with `C'. Note that all subpatterns in a Boolean search- pattern are regular expressions, unless option -F is used.- Options -E, -F, -G, -P, and -Z can be combined with --bool to- match subpatterns as strings or regular expressions (-E is the- default.) This option does not apply to -f FILE patterns.- Option --stats displays the search patterns applied. See also- options --and, --andnot, and --not.+ Specifies Boolean query patterns. A Boolean query pattern is+ composed of `AND', `OR', `NOT' operators and grouping with `('+ `)'. Spacing between subpatterns is the same as `AND', `|' is+ the same as `OR', and a `-' is the same as `NOT'. The `OR'+ operator binds more tightly than `AND'. For example, --bool+ 'A|B C|D' matches lines with (`A' or `B') and (`C' or `D'),+ --bool 'A -B' matches lines with `A' and not `B'. Operators+ `AND', `OR', `NOT' require proper spacing. For example, --bool+ 'A OR B AND C OR D' matches lines with (`A' or `B') and (`C' or+ `D'), --bool 'A AND NOT B' matches lines with `A' without `B'.+ Quoted subpatterns are matched literally as strings. For exam-+ ple, --bool 'A "AND"|"OR"' matches lines with `A' and also+ either `AND' or `OR'. Parenthesis are used for grouping. For+ example, --bool '(A B)|C' matches lines with `A' and `B', or+ lines with `C'. Note that all subpatterns in a Boolean query+ pattern are regular expressions, unless option -F is used.+ Options -E, -F, -G, -P, and -Z can be combined with --bool to+ match subpatterns as strings or regular expressions (-E is the+ default.) This option does not apply to -f FILE patterns.+ Option --stats displays the search patterns applied. See also+ options --and, --andnot, --not, --files, and --lines. --break Adds a line break between results from different files. -C NUM, --context=NUM Print NUM lines of leading and trailing context surrounding each- match. Places a --group-separator between contiguous groups of+ match. Places a --group-separator between contiguous groups of matches. See also options -A, -B, and -y. -c, --count- Only a count of selected lines is written to standard output.+ Only a count of selected lines is written to standard output. If -o or -u is specified, counts the number of patterns matched. If -v is specified, counts the number of non-matching lines. --color[=WHEN], --colour[=WHEN]- Mark up the matching text with the expression stored in the- GREP_COLOR or GREP_COLORS environment variable. WHEN can be+ Mark up the matching text with the expression stored in the+ GREP_COLOR or GREP_COLORS environment variable. WHEN can be `never', `always', or `auto', where `auto' marks up matches only when output on a terminal. The default is `auto'. --colors=COLORS, --colours=COLORS Use COLORS to mark up text. COLORS is a colon-separated list of- one or more parameters `sl=' (selected line), `cx=' (context- line), `mt=' (matched text), `ms=' (match selected), `mc='- (match context), `fn=' (file name), `ln=' (line number), `cn='+ one or more parameters `sl=' (selected line), `cx=' (context+ line), `mt=' (matched text), `ms=' (match selected), `mc='+ (match context), `fn=' (file name), `ln=' (line number), `cn=' (column number), `bn=' (byte offset), `se=' (separator). Param-- eter values are ANSI SGR color codes or `k' (black), `r' (red),- `g' (green), `y' (yellow), `b' (blue), `m' (magenta), `c'+ eter values are ANSI SGR color codes or `k' (black), `r' (red),+ `g' (green), `y' (yellow), `b' (blue), `m' (magenta), `c' (cyan), `w' (white). Upper case specifies background colors. A- `+' qualifies a color as bright. A foreground and a background- color may be combined with font properties `n' (normal), `f'+ `+' qualifies a color as bright. A foreground and a background+ color may be combined with font properties `n' (normal), `f' (faint), `h' (highlight), `i' (invert), `u' (underline). Param- eter `hl' enables file name hyperlinks. Parameter `rv' reverses- the `sl=' and `cx=' parameters with option -v. Selectively+ the `sl=' and `cx=' parameters with option -v. Selectively overrides GREP_COLORS. --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+ 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 specified on the command line. @@ -3671,146 +3697,146 @@ in markdown: --cpp Output file matches in C++. See also options --format and -u. - --csv Output file matches in CSV. If -H, -n, -k, or -b is specified,+ --csv Output file matches in CSV. If -H, -n, -k, or -b is specified, additional values are output. See also options --format and -u. -D ACTION, --devices=ACTION- If an input file is a device, FIFO or socket, use ACTION to- process it. By default, ACTION is `skip', which means that+ If an input file is a device, FIFO or socket, use ACTION to+ process it. By default, ACTION is `skip', which means that devices are silently skipped. If ACTION is `read', devices read just as if they were ordinary files. -d ACTION, --directories=ACTION- If an input file is a directory, use ACTION to process it. By- default, ACTION is `skip', i.e., silently skip directories+ If an input file is a directory, use ACTION to process it. By+ default, ACTION is `skip', i.e., silently skip directories unless specified on the command line. If ACTION is `read', warn- when directories are read as input. If ACTION is `recurse',+ when directories are read as input. If ACTION is `recurse', read all files under each directory, recursively, following sym-- bolic links only if they are on the command line. This is- equivalent to the -r option. If ACTION is `derefer-+ bolic links only if they are on the command line. This is+ equivalent to the -r option. If ACTION is `derefer- ence-recurse', read all files under each directory, recursively,- following symbolic links. This is equivalent to the -R option.+ following symbolic links. This is equivalent to the -R option. --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+ 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. --dotall- Dot `.' in regular expressions matches anything, including new-- line. Note that `.*' matches all input and should not be used.+ Dot `.' in regular expressions matches anything, including new-+ line. Note that `.*' matches all input and should not be used. -E, --extended-regexp- Interpret patterns as extended regular expressions (EREs). This+ Interpret patterns as extended regular expressions (EREs). This is the default. -e PATTERN, --regexp=PATTERN- Specify a PATTERN used during the search of the input: an input- line is selected if it matches any of the specified patterns.+ Specify a PATTERN used during the search of the input: an input+ line is selected if it matches any of the specified patterns. Note that longer patterns take precedence over shorter patterns.- This option is most useful when multiple -e options are used to- specify multiple patterns, when a pattern begins with a dash- (`-'), to specify a pattern after option -f or after the FILE+ This option is most useful when multiple -e options are used to+ specify multiple patterns, when a pattern begins with a dash+ (`-'), to specify a pattern after option -f or after the FILE arguments. --encoding=ENCODING- The encoding format of the input, where ENCODING can be:- `binary', `ASCII', `UTF-8', `UTF-16', `UTF-16BE', `UTF-16LE',- `UTF-32', `UTF-32BE', `UTF-32LE', `LATIN1', `ISO-8859-1',+ The encoding format of the input, where ENCODING can be:+ `binary', `ASCII', `UTF-8', `UTF-16', `UTF-16BE', `UTF-16LE',+ `UTF-32', `UTF-32BE', `UTF-32LE', `LATIN1', `ISO-8859-1', `ISO-8859-2', `ISO-8859-3', `ISO-8859-4', `ISO-8859-5', `ISO-8859-6', `ISO-8859-7', `ISO-8859-8', `ISO-8859-9',- `ISO-8859-10', `ISO-8859-11', `ISO-8859-13', `ISO-8859-14',- `ISO-8859-15', `ISO-8859-16', `MAC', `MACROMAN', `EBCDIC',- `CP437', `CP850', `CP858', `CP1250', `CP1251', `CP1252',+ `ISO-8859-10', `ISO-8859-11', `ISO-8859-13', `ISO-8859-14',+ `ISO-8859-15', `ISO-8859-16', `MAC', `MACROMAN', `EBCDIC',+ `CP437', `CP850', `CP858', `CP1250', `CP1251', `CP1252', `CP1253', `CP1254', `CP1255', `CP1256', `CP1257', `CP1258', `KOI8-R', `KOI8-U', `KOI8-RU'. --exclude=GLOB Skip files whose name matches GLOB using wildcard matching, same as -g ^GLOB. 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. When GLOB ends with a `/', directories- are excluded as if --exclude-dir is specified. Otherwise files- are excluded. Note that --exclude patterns take priority over- --include patterns. GLOB should be quoted to prevent shell+ \ to quote a wildcard or backslash character literally. When+ GLOB contains a `/', full pathnames are matched. Otherwise+ basenames are matched. When GLOB ends with a `/', directories+ are excluded as if --exclude-dir is specified. Otherwise files+ are excluded. Note that --exclude patterns take priority over+ --include patterns. GLOB should be quoted to prevent shell globbing. This option may be repeated. --exclude-dir=GLOB- Exclude directories whose name matches GLOB from recursive- searches, same as -g ^GLOB/. GLOB can use **, *, ?, and [...]- as wildcards, and \ to quote a wildcard or backslash character+ Exclude directories whose name matches GLOB from recursive+ searches, same as -g ^GLOB/. 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 pat-- terns. GLOB should be quoted to prevent shell globbing. This+ matched. Otherwise basenames are matched. Note that+ --exclude-dir patterns take priority over --include-dir pat-+ terns. GLOB should be quoted to prevent shell globbing. This option may be repeated. --exclude-from=FILE- Read the globs from FILE and skip files and directories whose- name matches one or more globs. A glob can use **, *, ?, and+ Read the globs from FILE and skip files and directories whose+ name matches one or more globs. A glob can use **, *, ?, and [...] as wildcards, and \ to quote a wildcard or backslash char- acter literally. When a glob contains a `/', full pathnames are- matched. Otherwise basenames are matched. When a glob ends- with a `/', directories are excluded as if --exclude-dir is- specified. Otherwise files are excluded. A glob starting with- a `!' overrides previously-specified exclusions by including- matching files. Lines starting with a `#' and empty lines in- FILE are ignored. When FILE is a `-', standard input is read.+ matched. Otherwise basenames are matched. When a glob ends+ with a `/', directories are excluded as if --exclude-dir is+ specified. Otherwise files are excluded. A glob starting with+ a `!' overrides previously-specified exclusions by including+ matching files. Lines starting with a `#' and empty lines in+ FILE are ignored. When FILE is a `-', standard input is read. This option may be repeated. --exclude-fs=MOUNTS- Exclude file systems specified by MOUNTS from recursive- searches, MOUNTS is a comma-separated list of mount points or- pathnames of directories on file systems. Note that- --exclude-fs mounts take priority over --include-fs mounts.+ Exclude file systems specified by MOUNTS from recursive+ searches, MOUNTS is a comma-separated list of mount points or+ pathnames of directories on file systems. Note that+ --exclude-fs mounts take priority over --include-fs mounts. This option may be repeated. -F, --fixed-strings- Interpret pattern as a set of fixed strings, separated by new-- lines, any of which is to be matched. This makes ugrep behave- as fgrep. If a PATTERN is specified, or -e PATTERN or -N PAT-- TERN, then this option has no effect on -f FILE patterns to- allow -f FILE patterns to narrow or widen the scope of the PAT-+ Interpret pattern as a set of fixed strings, separated by new-+ lines, any of which is to be matched. This makes ugrep behave+ as fgrep. If a PATTERN is specified, or -e PATTERN or -N PAT-+ TERN, then this option has no effect on -f FILE patterns to+ allow -f FILE patterns to narrow or widen the scope of the PAT- TERN search. -f FILE, --file=FILE- Read newline-separated patterns from FILE. White space in pat-+ Read newline-separated patterns from FILE. White space in pat- terns is significant. Empty lines in FILE are ignored. If FILE- does not exist, the GREP_PATH environment variable is used as- path to FILE. If that fails, looks for FILE in- /usr/local/share/ugrep/patterns. When FILE is a `-', standard+ does not exist, the GREP_PATH environment variable is used as+ path to FILE. If that fails, looks for FILE in+ /usr/local/share/ugrep/patterns. When FILE is a `-', standard input is read. Empty files contain no patterns; thus nothing is matched. This option may be repeated. --filter=COMMANDS Filter files through the specified COMMANDS first before search- ing. COMMANDS is a comma-separated list of `exts:command- [option ...]', where `exts' is a comma-separated list of file-- name extensions and `command' is a filter utility. The filter- utility should read from standard input and write to standard+ [option ...]', where `exts' is a comma-separated list of file-+ name extensions and `command' is a filter utility. The filter+ utility should read from standard input and write to standard output. Files matching one of `exts' are filtered. When `exts' is `*', files with non-matching extensions are filtered. One or- more `option' separated by spacing may be specified, which are- passed verbatim to the command. A `%' as `option' expands into- the pathname to search. For example, --filter='pdf:pdftotext %- -' searches PDF files. The `%' expands into a `-' when search-- ing standard input. Option --label=.ext may be used to specify+ more `option' separated by spacing may be specified, which are+ passed verbatim to the command. A `%' as `option' expands into+ the pathname to search. For example, --filter='pdf:pdftotext %+ -' searches PDF files. The `%' expands into a `-' when search-+ ing standard input. Option --label=.ext may be used to specify extension `ext' when searching standard input. --filter-magic-label=[+]LABEL:MAGIC- Associate LABEL with files whose signature "magic bytes" match- the MAGIC regex pattern. Only files that have no filename- extension are labeled, unless +LABEL is specified. When LABEL- matches an extension specified in --filter=COMMANDS, the corre-+ Associate LABEL with files whose signature "magic bytes" match+ the MAGIC regex pattern. Only files that have no filename+ extension are labeled, unless +LABEL is specified. When LABEL+ matches an extension specified in --filter=COMMANDS, the corre- sponding command is invoked. This option may be repeated. --format=FORMAT- Output FORMAT-formatted matches. For example --for-- mat='%f:%n:%O%~' outputs matching lines `%O' with filename `%f`- and line number `%n' followed by a newline `%~'. Context+ Output FORMAT-formatted matches. For example --for-+ mat='%f:%n:%O%~' outputs matching lines `%O' with filename `%f`+ and line number `%n' followed by a newline `%~'. Context options -A, -B, -C, and -y are ignored. See `man ugrep' section FORMAT. @@ -3822,15 +3848,15 @@ in markdown: behave as traditional grep. -g GLOBS, --glob=GLOBS- Search only files whose name matches the specified comma-sepa-+ Search only files whose name matches the specified comma-sepa- rated list of GLOBS, same as --include='glob' for each `glob' in- GLOBS. When a `glob' is preceded by a `!' or a `^', skip files- whose name matches `glob', same as --exclude='glob'. When- `glob' contains a `/', full pathnames are matched. Otherwise+ GLOBS. When a `glob' is preceded by a `!' or a `^', skip files+ whose name matches `glob', same as --exclude='glob'. When+ `glob' contains a `/', full pathnames are matched. Otherwise basenames are matched. When `glob' ends with a `/', directories- are matched, same as --include-dir='glob' and- --exclude-dir='glob'. A leading `/' matches the working direc-- tory. This option may be repeated and may be combined with+ are matched, same as --include-dir='glob' and+ --exclude-dir='glob'. A leading `/' matches the working direc-+ tory. This option may be repeated and may be combined with options -M, -O and -t to expand the recursive search. --group-separator[=SEP]@@ -3838,12 +3864,12 @@ in markdown: The default is a double hyphen (`--'). -H, --with-filename- Always print the filename with output lines. This is the+ Always print the filename with output lines. This is the default when there is more than one file to search. -h, --no-filename- Never print filenames with output lines. This is the default- when there is only one file (or only standard input) to search.+ Never print filenames with output lines. This is the default+ when there is only one file (or only standard input) to search. --heading, -+ Group matches per file. Adds a heading and a line break between@@ -3853,94 +3879,94 @@ in markdown: Display a help message, specifically on WHAT when specified. --hexdump=[1-8][a][b][c][h]- Output matches in 1 to 8 columns of 8 hexadecimal octets. The- default is 2 columns or 16 octets per line. Option `a' outputs- a `*' for all hex lines that are identical to the previous hex- line, `b' removes all space breaks, `c' removes the character- column and `h' removes hex spacing. Enables -X if -W or -X is+ Output matches in 1 to 8 columns of 8 hexadecimal octets. The+ default is 2 columns or 16 octets per line. Option `a' outputs+ a `*' for all hex lines that are identical to the previous hex+ line, `b' removes all space breaks, `c' removes the character+ column and `h' removes hex spacing. Enables -X if -W or -X is not specified. --hidden, -. Search hidden files and directories. --hyperlink- Hyperlinks are enabled for file names when colors are enabled.+ Hyperlinks are enabled for file names when colors are enabled. Same as --colors=hl. -I, --ignore-binary- Ignore matches in binary files. This option is equivalent to+ Ignore matches in binary files. This option is equivalent to the --binary-files=without-match option. -i, --ignore-case- Perform case insensitive matching. By default, ugrep is case- sensitive. By default, this option applies to ASCII letters+ Perform case insensitive matching. By default, ugrep is case+ sensitive. By default, this option applies to ASCII letters only. Use options -P and -i for Unicode case insensitive match- ing. --ignore-files[=FILE]- 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 of a FILE's location and in directories below are- ignored by temporarily overriding the --exclude and- --exclude-dir globs, as if --exclude-from=FILE is locally- enforced. Globbing is the same as --exclude-from=FILE and sup-- ports gitignore syntax, but directories are not automatically+ 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 of a FILE's location and in directories below are+ ignored by temporarily overriding the --exclude and+ --exclude-dir globs, as if --exclude-from=FILE is locally+ enforced. Globbing is the same as --exclude-from=FILE and sup-+ ports gitignore syntax, but directories are not automatically excluded from searches (use a glob ending with a `/' to identify- directories to ignore, same as git). Files and directories- explicitly specified as command line arguments are never+ directories to ignore, same as git). Files and directories+ 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, same as -g GLOB/. GLOB can use **, *, ?, and+ Only directories whose name matches GLOB are included in recur-+ sive searches, same as -g GLOB/. GLOB can use **, *, ?, and [...] as wildcards, and \ to quote a wildcard or backslash char-- acter literally. When GLOB contains a `/', full pathnames are- matched. Otherwise basenames are matched. Note that- --exclude-dir patterns take priority over --include-dir pat-- terns. GLOB should be quoted to prevent shell globbing. This+ acter literally. When GLOB contains a `/', full pathnames are+ matched. Otherwise basenames are matched. Note that+ --exclude-dir patterns take priority over --include-dir pat-+ terns. 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. A glob can use **, *, ?,- and [...] as wildcards, and \ to quote a wildcard or backslash+ Read the globs from FILE and search only files and directories+ whose name matches one or more globs. A glob can use **, *, ?,+ and [...] as wildcards, and \ to quote a wildcard or backslash character literally. When a glob contains a `/', full pathnames are matched. Otherwise basenames are matched. When a glob ends- with a `/', directories are included as if --include-dir is- specified. Otherwise files are included. A glob starting with- a `!' overrides previously-specified inclusions by excluding- matching files. Lines starting with a `#' and empty lines in- FILE are ignored. When FILE is a `-', standard input is read.+ with a `/', directories are included as if --include-dir is+ specified. Otherwise files are included. A glob starting with+ a `!' overrides previously-specified inclusions by excluding+ matching files. 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 like option -i, unless a pat-+ Perform case insensitive matching like option -i, unless a pat- tern is specified with a literal ASCII upper case letter. --json Output file matches in JSON. If -H, -n, -k, or -b is specified,@@ -3950,40 +3976,44 @@ 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. As-+ Displays the LABEL value when input is read from standard input+ where a file name would normally be printed in the output. As- sociates a filename extension with standard input when LABEL has a suffix. The default value is `(standard input)'. --line-buffered Force output to be line buffered instead of block buffered. + --lines+ Apply Boolean queries to match lines, the opposite of --files.+ This is the default Boolean query mode to match specific lines.+ -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@@ -3993,63 +4023,73 @@ 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. --mmap[=MAX]- Use memory maps to search files. By default, memory maps are- used under certain conditions to improve performance. When 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 unless a subpattern of PATTERN. Same as -e- (?^PATTERN). Negative PATTERN matches are essentially removed- before any other patterns are matched. Note that longer pat-+ Specify a negative PATTERN used during the search of the input:+ an input line is selected only if it matches any of the speci-+ fied patterns unless a subpattern of PATTERN. Same as -e+ (?^PATTERN). Negative PATTERN matches are essentially removed+ before any other patterns are matched. Note that longer pat- terns take precedence over shorter patterns. This option may be 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. --not [-e] PATTERN- Specifies that PATTERN should not match. Note that -e A --not- -e B matches lines with `A' or lines without a `B'. To match- lines with `A' that have no `B', specify -e A --andnot -e B.- Option --stats displays the search patterns applied. See also- options --and, --andnot, and --bool.+ Specifies that PATTERN should not match. Note that -e A --not+ -e B matches lines with `A' or lines without a `B'. To match+ lines with `A' that have no `B', specify -e A --andnot -e B.+ Option --stats displays the search patterns applied. See also+ options --and, --andnot, --bool, --files, and --lines. -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. + --files+ Apply Boolean queries to match files, the opposite of --lines.+ A file matches if all Boolean conditions are satisfied by the+ lines matched in the file. For example, --files -e A --and -e B+ -e C --andnot -e D matches a file if some lines match `A' and+ some lines match (`B' or `C') and no line in the file matches+ `D'. May also be specified as --files --bool 'A B|C -D'.+ Option -v cannot be specified with --files. See also options+ --and, --andnot, --not, --bool and --lines.+ -P, --perl-regexp Interpret PATTERN as a Perl regular expression using PCRE2. Note that Perl pattern matching differs from the default grep@@ -4811,7 +4851,7 @@ in markdown: - ugrep 3.3.12 December 11, 2021 UGREP(1)+ ugrep 3.4.0 December 20, 2021 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.71 for ugrep 3.3.+# Generated by GNU Autoconf 2.71 for ugrep 3.4. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,@@ -609,8 +609,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='ugrep' PACKAGE_TARNAME='ugrep'-PACKAGE_VERSION='3.3'-PACKAGE_STRING='ugrep 3.3'+PACKAGE_VERSION='3.4'+PACKAGE_STRING='ugrep 3.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1349,7 +1349,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 3.3 to adapt to many kinds of systems.+\`configure' configures ugrep 3.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1420,7 +1420,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in- short | recursive ) echo "Configuration of ugrep 3.3:";;+ short | recursive ) echo "Configuration of ugrep 3.4:";; esac cat <<\_ACEOF @@ -1562,7 +1562,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF-ugrep configure 3.3+ugrep configure 3.4 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc.@@ -2099,7 +2099,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 3.3, which was+It was created by ugrep $as_me 3.4, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw@@ -3586,7 +3586,7 @@ fi # Define the identity of the package. PACKAGE='ugrep'- VERSION='3.3'+ VERSION='3.4' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h@@ -9358,7 +9358,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 3.3, which was+This file was extended by ugrep $as_me 3.4, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES@@ -9426,7 +9426,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\-ugrep config.status 3.3+ugrep config.status 3.4 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\"
@@ -1,4 +1,4 @@-AC_INIT([ugrep],[3.3])+AC_INIT([ugrep],[3.4]) AM_INIT_AUTOMAKE([foreign]) AC_CONFIG_HEADERS([config.h]) AC_COPYRIGHT([Copyright (C) 2019-2021 Robert van Engelen, Genivia Inc.])
@@ -1,4 +1,4 @@-.TH UGREP "1" "December 11, 2021" "ugrep 3.3.12" "User Commands"+.TH UGREP "1" "December 20, 2021" "ugrep 3.4.0" "User Commands" .SH NAME \fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS@@ -67,7 +67,7 @@ pattern. For example, \fB\-e\fR \fIA\fR \fB\-e\fR \fIB\fR \fB\-\-and\fR \fB\-e\ (`A' or `B') and (`C' or `D'). Note that multiple \fB\-e\fR \fIPATTERN\fR are alternations that bind more tightly together than \fB\-\-and\fR. Option \fB\-\-stats\fR displays the search patterns applied. See also options-\fB\-\-not\fR, \fB\-\-andnot\fR, and \fB\-\-bool\fR.+\fB\-\-not\fR, \fB\-\-andnot\fR, \fB\-\-bool\fR, \fB\-\-files\fR, and \fB\-\-lines\fR. .TP \fB\-\-andnot\fR [[\fB\-e\fR] PATTERN] ... Combines \fB\-\-and\fR \fB\-\-not\fR. See also options \fB\-\-and\fR, \fB\-\-not\fR, and \fB\-\-bool\fR.@@ -98,7 +98,7 @@ matches alone. A match is considered binary when matching a zero byte or invalid UTF. Short options are \fB\-a\fR, \fB\-I\fR, \fB\-U\fR, \fB\-W\fR, and \fB\-X\fR. .TP \fB\-\-bool\fR, \fB\-%\fR-Specifies Boolean search patterns. A Boolean search pattern is+Specifies Boolean query patterns. A Boolean query pattern is composed of `AND', `OR', `NOT' operators and grouping with `(' `)'. Spacing between subpatterns is the same as `AND', `|' is the same as `OR', and a `\-' is the same as `NOT'. The `OR' operator binds@@ -112,12 +112,12 @@ literally as strings. For example, \fB\-\-bool\fR 'A "AND"|"OR"' matches lines with `A' and also either `AND' or `OR'. Parenthesis are used for grouping. For example, \fB\-\-bool\fR '(A B)|C' matches lines with `A' and `B', or lines with `C'. Note that all subpatterns in a Boolean-search pattern are regular expressions, unless option \fB\-F\fR is used.+query pattern are regular expressions, unless option \fB\-F\fR is used. Options \fB\-E\fR, \fB\-F\fR, \fB\-G\fR, \fB\-P\fR, and \fB\-Z\fR can be combined with \fB\-\-bool\fR to match subpatterns as strings or regular expressions (\fB\-E\fR is the default.) This option does not apply to \fB\-f\fR \fIFILE\fR patterns. Option \fB\-\-stats\fR displays the search patterns applied. See also options \fB\-\-and\fR,-\fB\-\-andnot\fR, and \fB\-\-not\fR.+\fB\-\-andnot\fR, \fB\-\-not\fR, \fB\-\-files\fR, and \fB\-\-lines\fR. .TP \fB\-\-break\fR Adds a line break between results from different files.@@ -461,6 +461,10 @@ a suffix. The default value is `(standard input)'. \fB\-\-line\-buffered\fR Force output to be line buffered instead of block buffered. .TP+\fB\-\-lines\fR+Apply Boolean queries to match lines, the opposite of \fB\-\-files\fR.+This is the default Boolean query mode to match specific lines.+.TP \fB\-M\fR \fIMAGIC\fR, \fB\-\-file\-magic\fR=\fIMAGIC\fR Only files matching the signature pattern MAGIC are searched. The signature "magic bytes" at the start of a file are compared to@@ -508,7 +512,7 @@ Specifies that PATTERN should not match. Note that \fB\-e\fR \fIA\fR \fB\-\-not matches lines with `A' or lines without a `B'. To match lines with `A' that have no `B', specify \fB\-e\fR \fIA\fR \fB\-\-andnot\fR \fB\-e\fR \fIB\fR. Option \fB\-\-stats\fR displays the search patterns applied. See also options \fB\-\-and\fR,-\fB\-\-andnot\fR, and \fB\-\-bool\fR.+\fB\-\-andnot\fR, \fB\-\-bool\fR, \fB\-\-files\fR, and \fB\-\-lines\fR. .TP \fB\-O\fR \fIEXTENSIONS\fR, \fB\-\-file\-extension\fR=\fIEXTENSIONS\fR Search only files whose filename extensions match the specified@@ -530,6 +534,16 @@ The line number of the matching line in the file is output without displaying the match. The line number counter is reset for each file processed. .TP+\fB\-\-files\fR+Apply Boolean queries to match files, the opposite of \fB\-\-lines\fR. A+file matches if all Boolean conditions are satisfied by the lines+matched in the file. For example, \fB\-\-files\fR \fB\-e\fR \fIA\fR \fB\-\-and\fR \fB\-e\fR \fIB\fR \fB\-e\fR \fIC\fR+\fB\-\-andnot\fR \fB\-e\fR \fID\fR matches a file if some lines match `A' and some lines+match (`B' or `C') and no line in the file matches `D'. May also+be specified as \fB\-\-files\fR \fB\-\-bool\fR 'A B|C \fB\-D\fR'. Option \fB\-v\fR cannot be+specified with \fB\-\-files\fR. See also options \fB\-\-and\fR, \fB\-\-andnot\fR, \fB\-\-not\fR,+\fB\-\-bool\fR and \fB\-\-lines\fR.+.TP \fB\-P\fR, \fB\-\-perl\-regexp\fR Interpret PATTERN as a Perl regular expression using PCRE2. Note that Perl pattern matching differs from the default grep POSIX
@@ -285,7 +285,7 @@ void CNF::OpTree::normalize(bool invert) else if (op == OR) op = AND; }- + // P&(Q&R) => P&Q&R // P|(Q|R) => P|Q|R auto i = list.begin();@@ -534,7 +534,7 @@ void CNF::new_pattern(PATTERN mask, const char *pattern) } } -// prune empty OR-terms and OR-terms with empty patterns that match anything+// prune empty OR terms and OR terms with empty patterns that match anything void CNF::prune() { // -x: empty patterns match empty lines@@ -547,7 +547,7 @@ void CNF::prune() while (i != e) {- // erase empty term and erase NULL term without NOT-OR terms, unless the first term and -f FILE is specified+ // erase empty term and erase NULL term without OR NOT terms, unless the first term and -f FILE is specified if ((i->empty() || (i->size() == 1 && (!i->front() || i->front()->empty()))) && (i != s || flag_file.empty())) terms.erase(i++); else@@ -597,10 +597,12 @@ void CNF::report(FILE *output) const if (empty()) return; + fprintf(output, flag_files ? "Files " : "Lines ");+ if (flag_fuzzy > 0)- fprintf(output, "Lines fuzzy-matched with max edit distance %zu if:" NEWLINESTR " ", flag_fuzzy & 255);+ fprintf(output, "fuzzy-matched with max edit distance %zu if:" NEWLINESTR " ", flag_fuzzy & 255); else- fprintf(output, "Lines matched if:" NEWLINESTR " ");+ fprintf(output, "matched if:" NEWLINESTR " "); if (!flag_file.empty()) {@@ -614,11 +616,13 @@ void CNF::report(FILE *output) const if (or_sep) fprintf(output, " or "); - fprintf(output, "%s", filename.c_str()); + fprintf(output, "%s", filename.c_str()); or_sep = true; } fprintf(output, " matches");+ if (flag_files)+ fprintf(output, " a line"); // if the first CNF term is left empty then we match -f FILE with additional constraints, i.e. not as an alternation if (terms.front().empty())@@ -647,9 +651,17 @@ void CNF::report(FILE *output) const else fprintf(output, "\"%s\"", (*j)->c_str()); if (j != i->begin())+ { fprintf(output, " does not match");+ if (flag_files)+ fprintf(output, " any line");+ } else+ { fprintf(output, " matches");+ if (flag_files)+ fprintf(output, " a line");+ } or_sep = true; and_sep = true;@@ -660,43 +672,52 @@ void CNF::report(FILE *output) const fprintf(output, NEWLINESTR); } -// return all OR-terms of the CNF joined together+// return all OR terms of the CNF joined together std::string CNF::adjoin() const { std::string adjoined;+ const char *sep = flag_basic_regexp ? "\\|" : "|"; - bool allnot = true;-- for (const auto& i : terms)+ if (flag_files) {- if (i.size() <= 1)- {- allnot = false;- break;- }+ // --files: join all OR and OR NOT terms+ for (const auto& i : terms)+ for (const auto& j : i)+ if (j && !j->empty())+ adjoined.append(*j).append(sep); }-- if (!allnot)+ else {- const char *sep = flag_basic_regexp ? "\\|" : "|";+ bool allnot = true; for (const auto& i : terms)- if (i.front() && !i.front()->empty())- adjoined.append(*i.front()).append(sep);-- if (!adjoined.empty()) {- // pop unused ending '|' (or BRE '\|')- adjoined.pop_back();- if (flag_basic_regexp)- adjoined.pop_back();+ if (i.size() <= 1)+ {+ allnot = false;+ break;+ } }++ // --lines: join all OR terms unless all of them are paired with OR NOT terms+ if (!allnot)+ for (const auto& i : terms)+ if (i.front() && !i.front()->empty())+ adjoined.append(*i.front()).append(sep);+ }++ if (!adjoined.empty())+ {+ // pop unused ending '|' (or BRE '\|')+ adjoined.pop_back();+ if (flag_basic_regexp)+ adjoined.pop_back(); } return adjoined; } -// return the first OR-terms of the CNF+// return the first OR terms of the CNF std::string CNF::first() const { if (!terms.empty() && terms.front().front())
@@ -79,6 +79,7 @@ extern bool flag_cpp; extern bool flag_csv; extern bool flag_decompress; extern bool flag_dereference;+extern bool flag_files; extern bool flag_files_with_matches; extern bool flag_files_without_match; extern bool flag_fixed_strings;
@@ -363,6 +363,8 @@ void Output::header(const char *& pathname, const std::string& partname, size_t // output "Binary file ... matches" void Output::binary_file_matches(const char *pathname, const std::string& partname) {+ if ((mode_ & BINARY) != 0)+ return; str(color_off); str("Binary file"); str(color_fn);@@ -394,6 +396,7 @@ void Output::binary_file_matches(const char *pathname, const std::string& partna str(color_off); str(" matches"); nl();+ mode_ |= BINARY; } // get a group capture's string pointer and size specified by %[ARG] as arg, if any
@@ -57,6 +57,9 @@ class Output { static constexpr size_t SIZE = 16384; // size of each buffer in the buffers container static constexpr size_t STOP = UNDEFINED_SIZE; // if last == STOP, cancel output+ static constexpr int FLUSH = 1; // mode bit: flush each line of output+ static constexpr int HOLD = 2; // mode bit: hold output+ static constexpr int BINARY = 4; // mode bit: binary file found struct Buffer { char data[SIZE]; }; // data buffer in the buffers container @@ -304,7 +307,7 @@ class Output { lock_(NULL), slot_(0), lineno_(0),- flush_(flag_line_buffered)+ mode_(flag_line_buffered ? FLUSH : 0) { grow(); }@@ -507,7 +510,7 @@ class Output { #ifdef OS_WIN chr('\r'); #else- ;+ { } #endif chr('\n'); check_flush();@@ -516,16 +519,38 @@ class Output { // enable line buffered mode to flush each line to output void set_flush() {- flush_ = true;+ mode_ |= FLUSH; } - // flush if output is line buffered+ // flush if output is line buffered to flush each line void check_flush() {- if (flush_)+ if (mode_ == FLUSH) flush(); } + // hold the output and do not flush, buffer all output until further notice+ void hold()+ {+ mode_ |= HOLD;+ }++ // launch output when held back+ void launch()+ {+ if ((mode_ & HOLD) != 0)+ {+ mode_ &= ~HOLD;+ check_flush();+ }+ }++ // return true when holding the output+ bool holding()+ {+ return mode_ & HOLD;+ }+ // synchronize output by threads on the given sync object void sync_on(Sync *s) {@@ -548,7 +573,7 @@ class Output { sync->acquire(lock_, slot_); } - // flush the buffers and acquire lock+ // acquire lock and flush the buffers, if not held back void flush() { if (buf_ != buffers_.begin() || cur_ > buf_->data)@@ -592,10 +617,22 @@ class Output { } } + // discard buffered output+ void discard()+ {+ buf_ = buffers_.begin();+ cur_ = buf_->data;+ }+ // flush output and release sync slot, if one was assigned with sync_on() void release() {- flush();+ if ((mode_ & HOLD) == 0)+ flush();+ else+ discard();++ mode_ = flag_line_buffered ? FLUSH : 0; if (sync != NULL) sync->release(lock_);@@ -655,7 +692,7 @@ class Output { // next buffer, allocate one if needed (when multi-threaded and lock is owned by another thread) void next() {- if (sync == NULL || sync->try_acquire(lock_))+ if ((mode_ & HOLD) == 0 && (sync == NULL || sync->try_acquire(lock_))) { flush(); }@@ -694,7 +731,7 @@ class Output { Buffers buffers_; // buffers container Buffers::iterator buf_; // current buffer in the container char *cur_; // current position in the current buffer- bool flush_; // true if output is line buffered+ int mode_; // bitmask 1 if line buffered 2 if hold };
@@ -63,6 +63,14 @@ void Stats::report(FILE *output) fprintf(output, "The following pathname selections and restrictions were applied:" NEWLINESTR); if (flag_config != NULL) fprintf(output, " --config=%s" NEWLINESTR, flag_config_file.c_str());+ if (flag_min_depth > 0 && flag_max_depth > 0)+ fprintf(output, " --depth=%zu,%zu" NEWLINESTR, flag_min_depth, flag_max_depth);+ else if (flag_min_depth > 0)+ fprintf(output, " --depth=%zu," NEWLINESTR, flag_min_depth);+ else if (flag_max_depth > 0)+ fprintf(output, " --depth=%zu" NEWLINESTR, flag_max_depth);+ if (flag_files)+ fprintf(output, " --files" NEWLINESTR); #ifdef WITH_HIDDEN if (flag_hidden) fprintf(output, " --hidden (default)" NEWLINESTR);@@ -74,12 +82,6 @@ void Stats::report(FILE *output) else fprintf(output, " --no-hidden (default)" NEWLINESTR); #endif- if (flag_min_depth > 0 && flag_max_depth > 0)- fprintf(output, " --depth=%zu,%zu" NEWLINESTR, flag_min_depth, flag_max_depth);- else if (flag_min_depth > 0)- fprintf(output, " --depth=%zu," NEWLINESTR, flag_min_depth);- else if (flag_max_depth > 0)- fprintf(output, " --depth=%zu" NEWLINESTR, flag_max_depth); for (auto& i : flag_ignore_files) fprintf(output, " --ignore-files='%s'" NEWLINESTR, i.c_str()); for (auto& i : ignore)
@@ -90,19 +90,21 @@ class Stats { // atomically update the number of matching files found, excluding files in archives returns true if max file matches (+ number of threads-1 when sorting) is not reached yet static bool found_file() {- if (flag_max_files > 0)- return fileno.fetch_add(1, std::memory_order_relaxed) < flag_max_files;- fileno.fetch_add(1, std::memory_order_relaxed);- return true;+ size_t n = fileno.fetch_add(1, std::memory_order_relaxed);+ return flag_max_files > 0 ? n < flag_max_files : true; } // atomically update the number of matching files found, including files in archives, returns true if max file matches (+ number of threads-1 when sorting) is not reached yet static bool found_part() {- if (flag_max_files > 0)- return partno.fetch_add(1, std::memory_order_relaxed) < flag_max_files;- partno.fetch_add(1, std::memory_order_relaxed);- return true;+ size_t n = partno.fetch_add(1, std::memory_order_relaxed);+ return flag_max_files > 0 ? n < flag_max_files : true;+ }++ // undo found_part+ static void undo_found_part()+ {+ partno.fetch_sub(1, std::memory_order_relaxed); } // the number of matching files found, excluding files in archives
@@ -317,6 +317,7 @@ bool flag_cpp = false; bool flag_csv = false; bool flag_decompress = false; bool flag_dereference = false;+bool flag_files = false; bool flag_files_with_matches = false; bool flag_files_without_match = false; bool flag_fixed_strings = false;@@ -648,6 +649,9 @@ struct Grep { // CNF of AND/OR/NOT matchers typedef std::list<std::list<std::unique_ptr<reflex::AbstractMatcher>>> Matchers; + // exit search exception+ struct EXIT_SEARCH : public std::exception { };+ // entry type enum class Type { SKIP, DIRECTORY, OTHER }; @@ -1050,11 +1054,14 @@ struct Grep { if (flag_max_line > 0 && lineno > flag_max_line) break; - // --max-files: max reached?- if (flag_invert_match && matches == 0 && !Stats::found_part())+ if (matches == 0 && flag_invert_match) {- stop = true;- break;+ // --max-files: max reached?+ if (!Stats::found_part())+ {+ stop = true;+ break;+ } } // -m: max number of matches reached?@@ -1268,11 +1275,14 @@ struct Grep { if (flag_max_line > 0 && lineno > flag_max_line) break; - // --max-files: max reached?- if (flag_invert_match && matches == 0 && !Stats::found_part())+ if (matches == 0 && flag_invert_match) {- stop = true;- break;+ // --max-files: max reached?+ if (!Stats::found_part())+ {+ stop = true;+ break;+ } } // -m: max number of matches reached?@@ -1581,11 +1591,14 @@ struct Grep { if (flag_max_line > 0 && lineno > flag_max_line) break; - // --max-files: max reached?- if (matches == 0 && !Stats::found_part())+ if (matches == 0) {- stop = true;- break;+ // --max-files: max reached?+ if (!Stats::found_part())+ {+ stop = true;+ break;+ } } // -m: max number of matches reached?@@ -1723,33 +1736,158 @@ struct Grep { virtual void search(const char *pathname); // check CNF AND/OR/NOT conditions are met for the line(s) spanning bol to eol- bool cnf_matching(const char *bol, const char *eol)+ bool cnf_matching(const char *bol, const char *eol, bool acquire = false) {- // for each AND term- for (const auto& i : *matchers)+ if (flag_files) {- auto j = i.begin();- auto e = i.end();+ if (out.holding())+ {+ size_t k = 0; // iterate over matching[] bitmask+ bool all = true; // all terms matched++ // for each AND term check if the AND term was matched before or has a match this time+ for (const auto& i : *matchers)+ {+ // an OR term hasn't matched before+ if (!matching[k])+ {+ auto j = i.begin();+ auto e = i.end();++ if (j != e)+ {+ // check OR terms+ if (*j && (*j)->buffer(const_cast<char*>(bol), eol - bol + 1).find() != 0)+ {+ matching[k] = true;+ ++j;+ }+ else+ {+ // check OR NOT terms+ size_t l = 0; // iterate over notmaching[k] bitmask+ bool none = true; // all not-terms matched++ while (++j != e)+ {+ if (*j && !notmatching[k][l])+ {+ if ((*j)->buffer(const_cast<char*>(bol), eol - bol + 1).find() != 0)+ notmatching[k][l] = true;+ else+ all = none = false;+ }++ ++l;+ }++ if (none)+ {+ // when all not-terms matched and we don't have a positive alternative then stop searching this file+ if (!*i.begin())+ throw EXIT_SEARCH();++ all = false;+ }+ }+ }+ }+ ++k;+ } - if (j != e)+ // if all terms matched globally per file then remove the hold to launch output+ if (all)+ {+ if (acquire)+ out.acquire();++ // --max-files: max reached?+ if (!Stats::found_part())+ throw EXIT_SEARCH();++ out.launch();+ }+ }+ }+ else+ {+ // for each AND term check if the line has a match+ for (const auto& i : *matchers) {- // check OR terms- if (*j && (*j)->buffer(const_cast<char*>(bol), eol - bol + 1).find() != 0)- continue;+ auto j = i.begin();+ auto e = i.end(); - // check OR NOT terms- while (++j != e)- if (*j && (*j)->buffer(const_cast<char*>(bol), eol - bol + 1).find() == 0)- break;+ if (j != e)+ {+ // check OR terms+ if (*j && (*j)->buffer(const_cast<char*>(bol), eol - bol + 1).find() != 0)+ continue; - if (j == e)- return false;+ // check OR NOT terms+ while (++j != e)+ if (*j && (*j)->buffer(const_cast<char*>(bol), eol - bol + 1).find() == 0)+ break;++ if (j == e)+ return false;+ } } } return true; } + // if CNF AND/OR/NOT conditions are met globally then launch output after searching a file with --files+ bool cnf_satisfied(bool acquire = false)+ {+ if (out.holding())+ {+ size_t k = 0; // iterate over matching[] bitmask++ // for each AND term check if the term was matched before+ for (const auto& i : *matchers)+ {+ // an OR term hasn't matched+ if (!matching[k])+ {+ // return if there are no OR NOT terms to check+ if (i.size() <= 1)+ return false;++ auto j = i.begin();+ auto e = i.end();++ // check if not all of the OR NOT terms matched+ if (j != e)+ {+ size_t l = 0; // iterate over notmaching[k] bitmask+ while (++j != e)+ {+ if (*j && !notmatching[k][l])+ break;+ ++l;+ }+ // return if all OR NOT terms matched+ if (j == e)+ return false;+ }+ }+ ++k;+ }++ if (acquire)+ out.acquire();++ // --max-files: max reached?+ if (!Stats::found_part())+ throw EXIT_SEARCH();++ out.launch();+ }++ return true;+ }+ // open a file for (binary) reading and assign input, decompress the file when -z, --decompress specified, may throw bad_alloc bool open_file(const char *pathname) {@@ -2930,38 +3068,38 @@ struct Grep { // after opening a file with init_read, check if it is binary bool init_is_binary() {- // limit checking to first buffer filled with input up to 4K, which should suffice, to improve performance+ // limit checking to first buffer filled with input up to 16K, which should suffice, to improve performance size_t avail = matcher->avail();- if (avail > 4096)- avail = 4096;- return is_binary(matcher->begin(), avail);- }-- const char *filename; // the name of the file being searched- std::string partname; // the name of an extracted file from an archive- std::string restline; // a buffer to store the rest of a line to search- Output out; // asynchronous output- reflex::AbstractMatcher *matcher; // the pattern matcher we're using, never NULL- Matchers *matchers; // the CNF of AND/OR/NOT matchers or NULL- MMap mmap; // mmap state- reflex::Input input; // input to the matcher- FILE *file; // the current input file+ return is_binary(matcher->begin(), avail < 16384 ? avail : 16384);+ }++ const char *filename; // the name of the file being searched+ std::string partname; // the name of an extracted file from an archive+ std::string restline; // a buffer to store the rest of a line to search+ Output out; // asynchronous output+ reflex::AbstractMatcher *matcher; // the pattern matcher we're using, never NULL+ Matchers *matchers; // the CNF of AND/OR/NOT matchers or NULL+ std::vector<bool> matching; // bitmap to keep track of globally matching CNF terms+ std::vector<std::vector<bool>> notmatching; // bitmap to keep track of globally matching OR NOT CNF terms+ MMap mmap; // mmap state+ reflex::Input input; // input to the matcher+ FILE *file; // the current input file #ifndef OS_WIN- StdInHandler stdin_handler; // a handler to handle non-blocking stdin from a TTY or a slow pipe+ StdInHandler stdin_handler; // a handler to handle non-blocking stdin from a TTY or a slow pipe #endif #ifdef HAVE_LIBZ- zstreambuf *zstream; // the decompressed stream from the current input file- std::istream *stream; // input stream layered on the decompressed stream+ zstreambuf *zstream; // the decompressed stream from the current input file+ std::istream *stream; // input stream layered on the decompressed stream #ifdef WITH_DECOMPRESSION_THREAD- std::thread thread; // decompression thread- std::atomic_bool thread_end; // true if decompression thread should terminate- int pipe_fd[2]; // decompressed stream pipe- std::mutex pipe_mutex; // mutex to extract files in thread- std::condition_variable pipe_zstrm; // cv to control new pipe creation- std::condition_variable pipe_ready; // cv to control new pipe creation- std::condition_variable pipe_close; // cv to control new pipe creation- volatile bool extracting; // true if extracting files from TAR or ZIP archive- volatile bool waiting; // true if decompression thread is waiting+ std::thread thread; // decompression thread+ std::atomic_bool thread_end; // true if decompression thread should terminate+ int pipe_fd[2]; // decompressed stream pipe+ std::mutex pipe_mutex; // mutex to extract files in thread+ std::condition_variable pipe_zstrm; // cv to control new pipe creation+ std::condition_variable pipe_ready; // cv to control new pipe creation+ std::condition_variable pipe_close; // cv to control new pipe creation+ volatile bool extracting; // true if extracting files from TAR or ZIP archive+ volatile bool waiting; // true if decompression thread is waiting #endif #endif @@ -3980,6 +4118,8 @@ void options(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, int a flag_file_magic.emplace_back(arg + 11); else if (strncmp(arg, "file-type=", 10) == 0) flag_file_type.emplace_back(arg + 10);+ else if (strcmp(arg, "files") == 0)+ flag_files = true; else if (strcmp(arg, "files-with-matches") == 0) flag_files_with_matches = true; else if (strcmp(arg, "files-without-match") == 0)@@ -4019,7 +4159,7 @@ void options(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, int a strcmp(arg, "format-open") == 0) usage("missing argument for --", arg); else- 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");+ usage("invalid option --", arg, "--file, --file-extension, --file-magic, --file-type, --files, --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':@@ -4104,8 +4244,10 @@ void options(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, int a flag_line_number = true; else if (strcmp(arg, "line-regexp") == 0) flag_line_regexp = true;+ else if (strcmp(arg, "lines") == 0)+ flag_files = false; else- usage("invalid option --", arg, "--label, --line-buffered, --line-number or --line-regexp");+ usage("invalid option --", arg, "--label, --line-buffered, --line-number, --line-regexp or --lines"); break; case 'm':@@ -5717,7 +5859,11 @@ void terminal() // --pager: if output is to a TTY then page through the results // open a pipe to a forked pager+#ifdef OS_WIN+ output = popen(flag_pager, "wb");+#else output = popen(flag_pager, "w");+#endif if (output == NULL) error("cannot open pipe to pager", flag_pager); @@ -6110,7 +6256,7 @@ void ugrep() // prune empty terms from the CNF that match anything bcnf.prune(); - // split the patterns at newlines, standard grep+ // split the patterns at newlines, standard grep behavior bcnf.split(); if (flag_file.empty())@@ -6151,6 +6297,13 @@ void ugrep() } } + // -v with --files is not permitted+ if (flag_files && flag_invert_match)+ {+ abort("-v is not permitted with --files, invert the Boolean query instead");+ flag_invert_match = false;+ }+ // -x or --match: enable -Y and disable --dotall and -w if (flag_line_regexp || flag_match) {@@ -6365,6 +6518,13 @@ void ugrep() // -q overrides -l and -L flag_files_with_matches = false; flag_files_without_match = false;++ // disable --format options+ flag_format_begin = NULL;+ flag_format_open = NULL;+ flag_format = NULL;+ flag_format_close = NULL;+ flag_format_end = NULL; } // -L: enable -l and flip -v i.e. -L=-lv and -l=-Lv@@ -6452,7 +6612,7 @@ void ugrep() matcher_options.append("T=").push_back(static_cast<char>(flag_tabs) + '0'); // --format-begin- if (!flag_quiet && flag_format_begin != NULL)+ if (flag_format_begin != NULL) format(flag_format_begin, 0); size_t nodes = 0;@@ -6712,7 +6872,7 @@ void ugrep() } // --format-end- if (!flag_quiet && flag_format_end != NULL)+ if (flag_format_end != NULL) format(flag_format_end, Stats::found_parts()); // --stats: display stats when we're done@@ -7657,6 +7817,28 @@ void Grep::search(const char *pathname) { size_t matches = 0; + // --files: reset the matching[] bitmask used in cnf_matching() for each matcher in matchers+ if (flag_files && matchers != NULL)+ {+ // hold the output+ out.hold();++ // reset the bit corresponding to each matcher in matchers+ size_t n = matchers->size();+ matching.resize(0);+ matching.resize(n);++ // reset the bit corresponding to the OR NOT terms of each matcher in matchers+ notmatching.resize(n);+ size_t j = 0;+ for (auto& i : *matchers)+ {+ notmatching[j].resize(0);+ notmatching[j].resize(i.size() > 0 ? i.size() - 1 : 0);+ ++j;+ }+ }+ if (flag_quiet || flag_files_with_matches) { // option -q, -l, or -L@@ -7664,24 +7846,37 @@ void Grep::search(const char *pathname) if (!init_read()) goto exit_search; - while (true)- {- matches = matcher->find() != 0;+ // --format: whether to out.acquire() early before Stats::found_part()+ bool acquire = flag_format != NULL && (flag_format_open != NULL || flag_format_close != NULL); - if (matches == 0 || matchers == NULL)+ while (matcher->find())+ {+ // --range: max line exceeded?+ if (flag_max_line > 0 && matcher->lineno() > flag_max_line) break; - const char *eol = matcher->eol(true); // warning: call eol() before bol() and end()- const char *bol = matcher->bol();+ if (matchers != NULL)+ {+ const char *eol = matcher->eol(true); // warning: call eol() before bol() and end()+ const char *bol = matcher->bol(); - // check CNF AND/OR/NOT matching- if (cnf_matching(bol, eol))- break;+ // check CNF AND/OR/NOT matching+ if (!cnf_matching(bol, eol, acquire) || out.holding())+ continue;+ }++ matches = 1;+ break; } - // --range: max line exceeded?- if (flag_max_line > 0 && matcher->lineno() > flag_max_line)- matches = 0;+ // --files: if we are still holding the output and CNF is finally satisfyable then a match was made+ if (flag_files && matchers != NULL)+ {+ if (!cnf_satisfied(acquire))+ goto exit_search;++ matches = 1;+ } // -v: invert if (flag_invert_match)@@ -7690,12 +7885,15 @@ void Grep::search(const char *pathname) if (matches > 0) { // --format-open or format-close: we must acquire lock early before Stats::found_part()- if (flag_files_with_matches && (flag_format_open != NULL || flag_format_close != NULL))+ if (acquire) out.acquire(); - // --max-files: max reached?- if (!Stats::found_part())- goto exit_search;+ if (!flag_files || matchers == NULL)+ {+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ } // -l or -L if (flag_files_with_matches)@@ -7744,16 +7942,53 @@ void Grep::search(const char *pathname) { // option -c - if (init_read())+ if (!init_read())+ goto exit_search;++ // --format: whether to out.acquire() early before Stats::found_part()+ bool acquire = flag_format != NULL && (flag_format_open != NULL || flag_format_close != NULL);++ if (flag_ungroup || flag_only_matching) {- if (flag_ungroup || flag_only_matching)+ // -co or -cu: count the number of patterns matched in the file++ while (matcher->find()) {- // -co or -cu: count the number of patterns matched in the file+ // --range: max line exceeded?+ if (flag_max_line > 0 && matcher->lineno() > flag_max_line)+ break; - while (matcher->find())+ if (matchers != NULL)+ {+ const char *eol = matcher->eol(true); // warning: call eol() before bol() and end()+ const char *bol = matcher->bol();++ // check CNF AND/OR/NOT matching, with --files acquire lock before Stats::found_part()+ if (!cnf_matching(bol, eol, acquire))+ continue;+ }++ ++matches;++ // -m: max number of matches reached?+ if (flag_max_count > 0 && matches >= flag_max_count)+ break;+ }+ }+ else+ {+ // -c without -o/-u: count the number of matching lines++ size_t lineno = 0;++ while (matcher->find())+ {+ size_t current_lineno = matcher->lineno();++ if (lineno != current_lineno) { // --range: max line exceeded?- if (flag_max_line > 0 && matcher->lineno() > flag_max_line)+ if (flag_max_line > 0 && current_lineno > flag_max_line) break; if (matchers != NULL)@@ -7761,8 +7996,8 @@ void Grep::search(const char *pathname) const char *eol = matcher->eol(true); // warning: call eol() before bol() and end() const char *bol = matcher->bol(); - // check CNF AND/OR/NOT matching- if (!cnf_matching(bol, eol))+ // check CNF AND/OR/NOT matching, with --files acquire lock before Stats::found_part()+ if (!cnf_matching(bol, eol, acquire)) continue; } @@ -7771,62 +8006,39 @@ void Grep::search(const char *pathname) // -m: max number of matches reached? if (flag_max_count > 0 && matches >= flag_max_count) break;- }- }- else- {- // -c without -o/-u: count the number of matching lines-- size_t lineno = 0;-- while (matcher->find())- {- size_t current_lineno = matcher->lineno();-- if (lineno != current_lineno)- {- // --range: max line exceeded?- if (flag_max_line > 0 && current_lineno > flag_max_line)- break;-- if (matchers != NULL)- {- const char *eol = matcher->eol(true); // warning: call eol() before bol() and end()- const char *bol = matcher->bol();-- // check CNF AND/OR/NOT matching- if (!cnf_matching(bol, eol))- continue;- }-- ++matches; - // -m: max number of matches reached?- if (flag_max_count > 0 && matches >= flag_max_count)- break;-- lineno = current_lineno;- }+ lineno = current_lineno; }+ } - // -c with -v: count non-matching lines- if (flag_invert_match)- {- matches = matcher->lineno() - matches;- if (matches > 0)- --matches;- }+ // -c with -v: count non-matching lines+ if (flag_invert_match)+ {+ matches = matcher->lineno() - matches;+ if (matches > 0)+ --matches; } } - // --format-open or --format-close: we must acquire lock early before Stats::found_part()- if (flag_format_open != NULL || flag_format_close != NULL)- out.acquire();+ // --files: if we are still holding the output and CNF is not satisfyable then no global matches were made+ if (flag_files && matchers != NULL)+ {+ if (!cnf_satisfied(acquire))+ goto exit_search; // we cannot report 0 matches and ensure accurate output+ }+ else+ {+ // --format-open or --format-close: we must acquire lock early before Stats::found_part()+ if (acquire)+ out.acquire(); - // --max-files: max reached?- if (matches > 0 || flag_format_open != NULL || flag_format_close != NULL)- if (!Stats::found_part())- goto exit_search;+ // --max-files: max reached?+ // unfortunately, allowing 'acquire' below produces "x matching + y in archives"+ // but without this we cannot produce correct format-open and format-close outputs+ if (matches > 0 || acquire)+ if (!Stats::found_part())+ goto exit_search;+ } if (flag_format != NULL) {@@ -7884,6 +8096,9 @@ void Grep::search(const char *pathname) if (!init_read()) goto exit_search; + // whether to out.acquire() early before Stats::found_part()+ bool acquire = flag_format_open != NULL || flag_format_close != NULL;+ if (flag_invert_match) { // FormatInvertMatchHandler requires lineno to be set precisely, i.e. after skipping --range lines@@ -7965,23 +8180,44 @@ void Grep::search(const char *pathname) const char *bol = matcher->bol(); // check CNF AND/OR/NOT matching- if (!cnf_matching(bol, eol))+ if (!cnf_matching(bol, eol, acquire)) continue; } // output --format-open if (matches == 0) {- // --format-open or --format-close: we must acquire lock early before Stats::found_part()- if (flag_format_open != NULL || flag_format_close != NULL)- out.acquire();+ if (flag_files && matchers != NULL)+ {+ // --format-open: we must acquire lock early before Stats::found_part()+ if (acquire && out.holding())+ {+ out.acquire(); - // --max-files: max reached?- if (!Stats::found_part())- goto exit_search;+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ }+ }+ else+ {+ // --format-open: we must acquire lock early before Stats::found_part()+ if (acquire)+ out.acquire();++ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ } if (flag_format_open != NULL)+ { out.format(flag_format_open, pathname, partname, Stats::found_parts(), matcher, false, Stats::found_parts() > 1);++ // --files: undo files count+ if (flag_files && matchers != NULL && out.holding())+ Stats::undo_found_part();+ } } ++matches;@@ -7997,6 +8233,11 @@ void Grep::search(const char *pathname) } } + // --files: if we are still holding the output and CNF is not satisfyable then no global matches were made+ if (flag_files && matchers != NULL)+ if (!cnf_satisfied(true))+ goto exit_search;+ // output --format-close if (matches > 0 && flag_format_close != NULL) out.format(flag_format_close, pathname, partname, Stats::found_parts(), matcher, false, Stats::found_parts() > 1);@@ -8033,9 +8274,12 @@ void Grep::search(const char *pathname) continue; } - // --max-files: max reached?- if (matches == 0 && !Stats::found_part())- goto exit_search;+ if (matches == 0 && (!flag_files || matchers == NULL))+ {+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ } ++matches; @@ -8113,9 +8357,12 @@ void Grep::search(const char *pathname) continue; } - // --max-files: max reached?- if (matches == 0 && !Stats::found_part())- goto exit_search;+ if (matches == 0 && (!flag_files || matchers == NULL))+ {+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ } if (binfile || (binary && !flag_hex && !flag_with_hex)) {@@ -8129,6 +8376,9 @@ void Grep::search(const char *pathname) matches = 1; } + if (flag_files && matchers != NULL && out.holding())+ continue;+ goto done_search; } @@ -8164,6 +8414,9 @@ void Grep::search(const char *pathname) matches = 1; } + if (flag_files && matchers != NULL && out.holding())+ continue;+ goto done_search; } @@ -8281,9 +8534,12 @@ void Grep::search(const char *pathname) if (matchers != NULL && !cnf_matching(bol, eol)) continue; - // --max-files: max reached?- if (matches == 0 && !Stats::found_part())- goto exit_search;+ if (matches == 0 && (!flag_files || matchers == NULL))+ {+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ } binary = flag_hex || (!flag_text && is_binary(bol, eol - bol)); @@ -8299,6 +8555,9 @@ void Grep::search(const char *pathname) matches = 1; } + if (flag_files && matchers != NULL && out.holding())+ continue;+ goto done_search; } @@ -8739,13 +8998,13 @@ void Grep::search(const char *pathname) matches = 1; } + if (flag_files && matchers != NULL && out.holding())+ continue;+ goto done_search; } } - if (!flag_invert_match)- ++matches;- // --range: max line exceeded? if (flag_max_line > 0 && current_lineno > flag_max_line) break;@@ -8754,9 +9013,17 @@ void Grep::search(const char *pathname) if (stop) goto exit_search; - // --max-files: max reached?- if (!flag_invert_match && matches == 0 && !Stats::found_part())- goto exit_search;+ if (!flag_invert_match)+ {+ if (matches == 0 && (!flag_files || matchers == NULL))+ {+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ }++ ++matches;+ } // -m: max number of matches reached? if (flag_max_count > 0 && matches >= flag_max_count)@@ -8785,6 +9052,9 @@ void Grep::search(const char *pathname) matches = 1; } + if (flag_files && matchers != NULL && out.holding())+ continue;+ goto done_search; } @@ -9141,6 +9411,9 @@ void Grep::search(const char *pathname) matches = 1; } + if (flag_files && matchers != NULL && out.holding())+ continue;+ goto done_search; } @@ -9154,9 +9427,14 @@ void Grep::search(const char *pathname) if (stop) goto exit_search; - // --max-files: max reached?- if (!flag_invert_match && matches == 0 && !Stats::found_part())- goto exit_search;+ if (matches == 0 && (!flag_files || matchers == NULL))+ {+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ }++ ++matches; // -m: max number of matches reached? if (flag_max_count > 0 && matches >= flag_max_count)@@ -9180,12 +9458,12 @@ void Grep::search(const char *pathname) matches = 1; } + if (flag_files && matchers != NULL && out.holding())+ continue;+ goto done_search; } - if (!flag_invert_match)- ++matches;- size_t border = matcher->border(); size_t first = matcher->first(); const char *begin = matcher->begin();@@ -9564,9 +9842,14 @@ void Grep::search(const char *pathname) if (stop) goto exit_search; - // --max-files: max reached?- if (!flag_invert_match && matches == 0 && !Stats::found_part())- goto exit_search;+ /* logically OK but dead code because -v+ if (matches == 0 && !flag_invert_match && (!flag_files || matchers == NULL))+ {+ // --max-files: max reached?+ if (!Stats::found_part())+ goto exit_search;+ }+ */ // -m: max number of matches reached? if (flag_max_count > 0 && matches >= flag_max_count)@@ -9586,16 +9869,18 @@ void Grep::search(const char *pathname) { matches = 0; }- else if (flag_invert_match)+ else // if (flag_invert_match) is true { lineno = last_lineno = current_lineno + matcher->lines() - 1; continue; }+ /* logically OK but dead code because -v else { out.binary_file_matches(pathname, partname); matches = 1; }+ */ goto done_search; }@@ -9678,16 +9963,18 @@ void Grep::search(const char *pathname) { matches = 0; }- else if (flag_invert_match)+ else // if (flag_invert_match) is true { lineno = last_lineno = current_lineno + matcher->lines() - 1; continue; }+ /* logically OK but dead code because -v else { out.binary_file_matches(pathname, partname); matches = 1; }+ */ goto done_search; }@@ -9870,16 +10157,18 @@ void Grep::search(const char *pathname) { matches = 0; }- else if (flag_invert_match)+ else // if (flag_invert_match) is true { lineno = last_lineno = current_lineno + matcher->lines() - 1; continue; }+ /* logically OK but dead code because -v else { out.binary_file_matches(pathname, partname); matches = 1; }+ */ goto done_search; }@@ -9960,6 +10249,11 @@ void Grep::search(const char *pathname) done_search: + // --files: check if all CNF conditions are met globally to launch output or reset matches+ if (flag_files && matchers != NULL)+ if (!cnf_satisfied())+ matches = 0;+ // any matches in this file or archive? if (matches > 0) matched = true;@@ -9969,6 +10263,11 @@ done_search: out.nl(); } + catch (EXIT_SEARCH&)+ {+ // --files: cnf_matching() rejected a file, no need to search this file any further+ }+ catch (...) { // this should never happen@@ -10424,7 +10723,7 @@ void help(std::ostream& out) (`A' or `B') and (`C' or `D'). Note that multiple -e PATTERN are\n\ alternations that bind more tightly together than --and. Option\n\ --stats displays the search patterns applied. See also options\n\- --not, --andnot, and --bool.\n\+ --not, --andnot, --bool, --files, and --lines.\n\ --andnot [[-e] PATTERN] ...\n\ Combines --and --not. See also options --and, --not, and --bool.\n\ -B NUM, --before-context=NUM\n\@@ -10450,7 +10749,7 @@ void help(std::ostream& out) matches alone. A match is considered binary when matching a zero\n\ byte or invalid UTF. Short options are -a, -I, -U, -W, and -X.\n\ --bool, -%\n\- Specifies Boolean search patterns. A Boolean search pattern is\n\+ Specifies Boolean query patterns. A Boolean query pattern is\n\ composed of `AND', `OR', `NOT' operators and grouping with `(' `)'.\n\ Spacing between subpatterns is the same as `AND', `|' is the same\n\ as `OR', and a `-' is the same as `NOT'. The `OR' operator binds\n\@@ -10464,12 +10763,12 @@ void help(std::ostream& out) lines with `A' and also either `AND' or `OR'. Parenthesis are used\n\ for grouping. For example, --bool '(A B)|C' matches lines with `A'\n\ and `B', or lines with `C'. Note that all subpatterns in a Boolean\n\- search pattern are regular expressions, unless option -F is used.\n\+ query pattern are regular expressions, unless option -F is used.\n\ Options -E, -F, -G, -P, and -Z can be combined with --bool to match\n\ subpatterns as strings or regular expressions (-E is the default.)\n\ This option does not apply to -f FILE patterns. Option --stats\n\ displays the search patterns applied. See also options --and,\n\- --andnot, and --not.\n\+ --andnot, --not, --files, and --lines.\n\ --break\n\ Adds a line break between results from different files.\n\ -C NUM, --context=NUM\n\@@ -10774,6 +11073,9 @@ void help(std::ostream& out) a suffix. The default value is `(standard input)'.\n\ --line-buffered\n\ Force output to be line buffered instead of block buffered.\n\+ --lines\n\+ Apply Boolean queries to match lines, the opposite of --files.\n\+ This is the default Boolean query mode to match specific lines.\n\ -M MAGIC, --file-magic=MAGIC\n\ Only files matching the signature pattern MAGIC are searched. The\n\ signature \"magic bytes\" at the start of a file are compared to\n\@@ -10813,7 +11115,7 @@ void help(std::ostream& out) matches lines with `A' or lines without a `B'. To match lines with\n\ `A' that have no `B', specify -e A --andnot -e B. Option --stats\n\ displays the search patterns applied. See also options --and,\n\- --andnot, and --bool.\n\+ --andnot, --bool, --files, and --lines.\n\ -O EXTENSIONS, --file-extension=EXTENSIONS\n\ Search only files whose filename extensions match the specified\n\ comma-separated list of EXTENSIONS, same as --include='*.ext' for\n\@@ -10831,6 +11133,15 @@ void help(std::ostream& out) The line number of the matching line in the file is output without\n\ displaying the match. The line number counter is reset for each\n\ file processed.\n\+ --files\n\+ Apply Boolean queries to match files, the opposite of --lines. A\n\+ file matches if all Boolean conditions are satisfied by the lines\n\+ matched in the file. For example, --files -e A --and -e B -e C\n\+ --andnot -e D matches a file if some lines match `A' and some lines\n\+ match (`B' or `C') and no line in the file matches `D'. May also\n\+ be specified as --files --bool 'A B|C -D'. Option -v cannot be\n\+ specified with --files. See also options --and, --andnot, --not,\n\+ --bool and --lines.\n\ -P, --perl-regexp\n\ Interpret PATTERN as a Perl regular expression" #if defined(HAVE_PCRE2)
@@ -38,7 +38,7 @@ #define UGREP_HPP // ugrep version-#define UGREP_VERSION "3.3.12"+#define UGREP_VERSION "3.4.0" // disable mmap because mmap is almost always slower than the file reading speed improvements since 3.0.0 #define WITH_NO_MMAP
@@ -124,9 +124,12 @@ for PAT in '' 'Hello' '\w+\s+\S+' '\S\n\S' 'nomatch' ; do $UG -U -IPx "$PAT" $FILES > "out/$FN-IPx.out" done -for PAT in '' 'Hello World' 'Hello -World' 'Hello -World|greeting' 'Hello -(greeting|World)' '"a Hello" greeting' ; do+for PAT in '' 'Hello World' 'Hello -World' 'Hello -bin' 'bin -Hello' 'bin -greeting' 'Hello -World|greeting' 'Hello -bin|greeting' 'Hello -(greeting|World)' '"a Hello" greeting' ; do FN=`echo "Hello_$PAT" | tr -Cd '[:alnum:]_-'`- $UG -U --bool "$PAT" $FILES > "out/$FN--bool.out"+ for OPS in '' '-l' '-c' '-co' '-o' '-C2' '-y' '--json' ; do+ $UG -U --bool $OPS "$PAT" $FILES > "out/$FN--bool$OPS.out"+ $UG -U --files --bool $OPS "$PAT" $FILES > "out/$FN--files--bool$OPS.out"+ done done $UG -U -e 'Hello' --and 'World' $FILES > "out/Hello--and.out"
tests/out/Hello_--bool--json.out
@@ -0,0 +1,186 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "#!/bin/sh" },+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Êþº¾\u0000\u0000\u00004\u0000\u001d" },+ { "match": "\u0000\u0006\u0000\u000f\t\u0000\u0010\u0000\u0011\b\u0000\u0012" },+ { "match": "\u0000\u0013\u0000\u0014\u0007\u0000\u0015\u0007\u0000\u0016\u0001\u0000\u0006<init>\u0001\u0000\u0003()V\u0001\u0000\u0004Code\u0001\u0000\u000fLineNumberTable\u0001\u0000\u0004main\u0001\u0000\u0016([Ljava/lang/String;)V\u0001\u0000" },+ { "match": "SourceFile\u0001\u0000" },+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" },+ { "match": "\u0000\u0000\u0000\u0006\u0000\u0001\u0000\u0000\u0000\u0003\u0000\t\u0000\u000b\u0000\f\u0000\u0001\u0000\t\u0000\u0000\u0000%\u0000\u0002\u0000\u0001\u0000\u0000\u0000\t²\u0000\u0002\u0012\u0003¶\u0000\u0004±\u0000\u0000\u0000\u0001\u0000" },+ { "match": "\u0000\u0000\u0000" },+ { "match": "\u0000\u0002\u0000\u0000\u0000\u0005\u0000\b\u0000\u0006\u0000\u0001\u0000\r\u0000\u0000\u0000\u0002\u0000\u000e" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "import java.lang.*;" },+ { "match": "" },+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": "{ public static void main(String[] arg)" },+ { "match": " { System.out.println(\"Hello World!\");" },+ { "match": " }" },+ { "match": "}" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "%PDF-1.3" },+ { "match": "%Äåòåë§ó ÐÄÆ" },+ { "match": "4 0 obj" },+ { "match": "<< /Length 5 0 R /Filter /FlateDecode >>" },+ { "match": "stream" },+ { "match": "x\u0001EŽ»" },+ { "match": "\u00021\u0014D{¿â”Z˜½‰y˜V\u0011l\u0017.ø\u0001a-d×eÍÿƒ\u0017,¬†™9\f³1²Q\u0002¹F—â©\u0012ó™�\\LY" },+ { "match": "Ÿ‰\u0007o†k÷´ŽÐ›áâj©Rj²@8þí” »¶pQ£DÄ£\rï iÂ\u000bº0¨z¬|²¿Oó¼\u001eÐ\u00177µ7ã\u0017Nÿ ¥" },+ { "match": "endstream" },+ { "match": "endobj" },+ { "match": "5 0 obj" },+ { "match": "123" },+ { "match": "endobj" },+ { "match": "2 0 obj" },+ { "match": "<< /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792]" },+ { "match": ">>" },+ { "match": "endobj" },+ { "match": "6 0 obj" },+ { "match": "<< /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R" },+ { "match": ">> >>" },+ { "match": "endobj" },+ { "match": "9 0 obj" },+ { "match": "<< /Length 10 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >>" },+ { "match": "stream" },+ { "match": "x\u0001…U]h\u001cU\u0014>»sg\u0003\u0012\u0007\u001f´\r-´ƒ?m\té2‰V\u0013‹µÛMºI\u0013·ëfS›*Êtv6;Ídfœ™Ý&¡O¥à›\u0016\u0004é« >Æ‚\b¶*6/ö¥¥Å’J5\u000f" },+ { "match": "\u0011ZŒ (}Rð;3ÛdvA2Ã�ùî¹çž{Îwî¹—¨ëoÝóì´J4ç„~¡œ›>9}JíºMiR¨›ðèFàåJ¥\tÆŽë˜üo\u001eÞ¥\u0014Kîìg[íc[öäª\u0019\u0018к†æV\u0003cŽ(¥\u0011ej†ç‡D]— \u001f<\u001bzŒo\u0003?9[)ç�×€•Ö\\@zª`:¦o\u0019jÁ×\u0017Ô’ïÖ,;éëVãlcËgÎn°¯üìFë\u000ef'Çñï…Ï\u0017Lgj\u0012x\u001fð’¡�0î\u0003¾Û´N\u0014cœN{á‘r¬ŸÎ6f§r-ùÉštª%¿PoŒ2Î\u0012¥—\u0016ë•7€Ÿ\u0000^uN\u0017�·ô×gÝq¶ÓC$õ\u0018Aþ\u0014ð³ÀZÝ\u001cã<©À\u0015ß-³>Ëê9<\u0002ü2ð%+\u001c«\u0000þôCМd9° ÅzžýÄZ\"{F?V\u0002Þ\u0006|È´\u000b¼\u0016숊\u0017–Øæ ð¼c\u0017y-Ä..›A\u0014/b\u0017?…õÊh¬/§C¿ÂsŸ&’÷Ô¬£cÀàD\u001eû£,‡?rèÙÑÞz\u0011xÉo”9ö=Àkº?R\u0000†ÍÌcU}˜y~\u0001x€N¤t2É¥Óø\u001aäпˆ7 ‹š\u0011òÈÇX\r}›" },+ { "match": "ÐpÐ|ô\fh\u0015€tZ\u0000*%´LôX'ž£R\u0015=•f¢YA„ØÊý¨oP~×§Ô€´Në�Ö�^£_\"É<ýJsèç!m`l¦Ãn\u001e^8´\b\u000fØ\u0013¶ù eÓ\u0015Û…&žG;(&Ä+bP\f‘*^\u0015‡Å!1\fé�8\u0018͉½OúÎ~>ذô.ÖMú¾\f\u000eB¬gÃ3\u0007¬p4\u0001<ø\u0007ëÎFš\t¶.îhìó¼�Þ?ï¿c\u0019·>ø³�½\u0000ú1'¿Á¢\u000bk&%æ^?÷MOÂCuE|õÖ�îëçèx2KQÞª�Y’×äûò" },+ { "match": "¾÷äÕ¤\rùgy\u0015ï½¶\\=Ê\u000bÿ“¹Í!F;’ÍAÎ<›Q´qÆ\u001bÀ!¸©Esö·YL²é¶b´`ÉB”�«¸ÿË\tóÃ<·±Rs.îð¼·?c6Í÷Š\u000f‹t¾O»¬kŸh?jh+ÚÇ@¿K\u001fJ_JßJW¤«Ò\rR¥kÒ²ô�ô½ô¹ô5z_@º,]éØIqì\u001b»\u0007~Æ{Öhí0f†³\u0014\u0010óÂÚÌ" },+ { "match": "K\u001fñw\u0006c›ù3¡Õ^\u0003�»c-刲SyF\u0019Vv+Ï)\u0013J¯r@9¬lW\u0006Ðú•Qe/Fvn°dc=΀…’g‹¦#®â<±Wu°çÃK\u001dï¦_\\ÃÖ†5ØI=\u000ežÙÚ¦\u000e¯\u0011W¿\u0015Uc¼;]œ\u0006:M!b‹Î\"r\u001f:œ\u001f'ªþÎÙ\\“85Roâ”°Ä.Ñ/ÆZ5˜\u0013\u0007P…ãmõ8ÈUš\u0019É\fgr¤fz3C™þÌ1ÆQ¬Ñù’Ù‹Ñ!|G\u0012Þ3Ë1ÿ›5Äg\u0018ï\u001dæ¨\tl£‡[+4çqß\u0011å]oÁ·fê¡: i/©9\\¯¦:æ\u0018Ù>U·m5\u001a" },+ { "match": "Tß\fL¿iV³Äw7Ï#úëõèNNm»a4üf,£Tê&Ñ·�“4" },+ { "match": "endstream" },+ { "match": "endobj" },+ { "match": "10 0 obj" },+ { "match": "1116" },+ { "match": "endobj" },+ { "match": "7 0 obj" },+ { "match": "[ /ICCBased 9 0 R ]" },+ { "match": "endobj" },+ { "match": "3 0 obj" },+ { "match": "<< /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 2 0 R ] >>" },+ { "match": "endobj" },+ { "match": "11 0 obj" },+ { "match": "<< /Type /Catalog /Pages 3 0 R >>" },+ { "match": "endobj" },+ { "match": "8 0 obj" },+ { "match": "<< /Type /Font /Subtype /TrueType /BaseFont /GQTMZF+Menlo-Regular /FontDescriptor" },+ { "match": "12 0 R /Encoding /MacRomanEncoding /FirstChar 72 /LastChar 111 /Widths [ 602" },+ { "match": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 602 0 0 0 0 0 0 602" },+ { "match": "0 0 602 ] >>" },+ { "match": "endobj" },+ { "match": "12 0 obj" },+ { "match": "<< /Type /FontDescriptor /FontName /GQTMZF+Menlo-Regular /Flags 33 /FontBBox" },+ { "match": "[-558 -375 718 1041] /ItalicAngle 0 /Ascent 928 /Descent -236 /CapHeight 729" },+ { "match": "/StemV 99 /XHeight 547 /StemH 83 /AvgWidth 602 /MaxWidth 602 /FontFile2 13 0 R" },+ { "match": ">>" },+ { "match": "endobj" },+ { "match": "13 0 obj" },+ { "match": "<< /Length 14 0 R /Length1 4064 /Filter /FlateDecode >>" },+ { "match": "stream" },+ { "match": "x\u0001ÝW{xTÅ\u0015?sw6¯Í>’MHH€]Öå•,�„·R\u0016Hxˆ /ë.ˆòH (!\bA´1�JQ\tÁ@…\bH}\u0015Q©µ+E]\tÄT¤b#E„ \u0002" },+ { "match": "ø¢hŠ\u0014!Ø\u0000CϽ\u001bý>í×ïë¿íÜ�3çüæÌyÝ»÷Δ-\\\\DVª$P`VÉŒ\u0005d6ëI\u001eŠgÝSæ6Eн—HË�½`NITŽ‘åNsæÝ7;*'Nfy@qь¨LWxìWÌ@T\u0016}x¼®¸¤Œí\u0018Íú.\u0013×¼ÒYmó‰£\f°dƽmþé8Ëîù3JŠxäf�0é¶ tQ™)’½šÇì\u0005\u000b‹ÚôE�(¦St®�\u001a–\u0005w©Y)‹î\"\u000biä �”ÄЬ+yÖ˜×b²–>}ö�;ì7\\¤N±æâ½eéy\u0006s(¸¤ßå•W…¬�½…Åè¤1ÁëbJT\u0007\"ýàå•×’e½iɘù¾É\bÅf½®UŠ”íë¦É¡™\"…j\tL+I\u0017.RÌ'›4‰\u0003‚pš¼Ã¤vÚĈÍä\u0013·=R\u000eõ‰Dª`ÌJ>¦\t”Ë4Þ´\u0017gjÅ’�‘\u0018“·˜:Òäu\u0013‡‰h&\"\u0002!\u0005¥pµ\u0002W\u0014.+´æâŸuø®\u0002—Zªå%…K\rzËÅ�l©FK¥~ñB\u0017y1„‹\u0001ýB\u0017|{>G~ÛŠó9ø‡Â9…orqÖ…¿×¢™ClVhŽ\\;\u0018¸¦=\u0012_�)”_ÕâL!þ¦púË\fyZáË\f|¡ðù]øLáÓ:œ:™.Oµâd:NÔâ\u0013…�\u0015Ž\u001fK‘Ç\u0015Ž¥àh->ú0E~¤ðáê\u0004ùa" },+ { "match": ">¨À‘Ahb¡i\u0010\u000e+\u001cz?^\u001eRx?\u001e\u0007\u0015ÞS8På”\u00072ñ×TìWx·\u0016�«|²Qá/" },+ { "match": "ïT`ŸÂÛ" },+ { "match": "VØ»)Q¾¥°GáM…?)4°½\u0006\u0017Þ°¢~w�¬WؽkšÜ]‡Ý•ú®:ŸÜ5\r»\u0002z�\u000f;\u0015^¯E¤f¨|MáU\u001e^mÅ+lk‡Â\u001f\u000b±½\u0010/Û\u0010NÂ\u001f\u0014^R�«ø½Â‹" },+ { "match": "¿KÂ6…\u0017ž·É\u0017rñ¼\rÏmuÊçºa«\u0013ÏnñËg+°Å�ß*<£ð´ÂSO¦Ë§" },+ { "match": "ñä\u0013\u000eùd:žpà7ñجð8;y\\aS\"6nè)7*lè‰ÇØÿcµ¨]_'k\u0015Öó³µ¾\u000eë+õuk|rÝ4¬\u000bè�*üZa-Ëkë°Æ‡\u001a.FÍP<ÂÙ>âÂê\u0004T3P]ˆU\\´U>T9±Ráa…‡\u0014\u001e\\á”\u000f*¬pâW" },+ { "match": "Ë\u0015\u001ep\u000e“\u000fLÂ/\u0015*ïŲ¥\u0015r™ÂÒ" },+ { "match": "TtÄý" },+ { "match": "å6üBa‰Â=" },+ { "match": "‹Ë¬r±\u001d‹#‚\u0002Gõ2+Ê\u001aôEIX\u0014Ð\u0017*ܰ@¡tþ$YZ‹ù%ÝäüI(é†y" },+ { "match": "wåâN…¹¹(nÅœ:ÌV(R(T˜5³£œ¥0“\u001crfGÌP˜®p‡ÂíS\u0012äí6L+Ämû0•…©.LI\u0000?ÑA\u0017nUø¹Â-\u0019éò–\\LV˜¤0QaB\u0005Æ+ÜìÂ8…±Â/Ç*ÜT‡1Ýpãè4ycŒ\u001ež$G§aTAš\u001c¥0’¥‘…\u0018ÁÒˆ:\u0014¤!Ÿ�üþ\u0018>Ì)‡'axD\u000b\u0004âôaCír˜\u0013Ã\"\u001a±44`“Cí\u0018\u001a\u0011\r,\u0005†XeÀ†@DT²4Ä\u001a'‡X1$\"\u0002�Býg" },+ { "match": "ƒ9„Á¸Aáún\u0018¤0�\u000b<°\u0010\u0003z·—\u0003Æ ¿B?¿KöSè;\u0006}zµ—}Æ �‡<…\\VÌUèÍÓ½Û£W{ä0—“†žq©²g\u001düÙÉÒï‚?¢\u0019n³\u001dN™�Œl#ÜZ=«‡Of)ô`Í\u001e>t×\u0006Éî" },+ { "match": "Ý\u0014º*t±Ã—:Lú" },+ { "match": "p�\u001d^…Îv»ì¬àqû¥§\u0002n?:�AGöÜQ¡ƒB&×6S!ƒïJF:Ú+¤+¤)´c\u000bíF 5Å/S‡!Åå�)~¸\u001cHf½d\u0017’x}’‚“3w\u000eƒƒ=8œpDkg·Y¥Ý\u000e{´v¶Äxi³Â\u0016]\"×.1\u001e‰\\»\u001dº5\u000eVãÙê¯'(Äs&ñ" },+ { "match": "q©ˆu FÁ¦-" },+ { "match": "Ò\u0005prh…Æ€6\b‚\u0003\u0010~�\u0003\"\"" },+ { "match": "W¬\u0016Yÿ?�þÇSáOg„\u001a;M¬åÑØGDè!m\u0019¥¿¿\"´‡u4S/\"\u001aÅJ±“ù¼·h¤åt^ÄãmÑŸ¹z^\u001bÔ=ŒÖÐfsu\rNÓbì¢Cô\u000e\u001dcî´\u0018\b^+\u000e‘Gœ`?+ð¡¡ž¥=LËQ� è$Jh‹x‰-–SD”Ò2�Gm\"[Þ¯\u001fdt?=Ä×£´…J™72XÎñL;h\u0015] \rÚ\u0019šÂüNÚËñ(þüš¹ˆ&jaKÛ´ÁÚlÖÛËÖ6Ñ&±œšh‘Nü)WtJ6iYlu\u0007g@4“6Ë&¹Á¨\u0007�Mò\u001cÏ\u0010u°D,®\u0018/gaÔn«Ø%zkãè\u0010¯/§É¸\rwã˜X¡{õ%8C5\u001aa:ÝI\u0007d“ÅE51^ª±Ì\u0016÷éÓÍ«œ•kKôéb\u001b�a›3ñ\u001dË\u001eŽl³™1Ñ\u000em¢\u001c'Çqγ\u0019ÛlÒš(µ8h?Z¹îk5%Fé#0„ó)×o¢\rô\fÛíÊ•!*E_ö^Jåruô¢m|ùåjÔrEÍjˆ<m0mÖf‹U\u001cm\u000bW³\u0014ùÔŸ}t�gi…ØÁqSL\u0005-’M¼U$êAôZŒEêü÷¦l·#¬ùF\u0017†\u0003\u0013‚î}!�?û'¢Û\u0011ã\u000eÓøpâ}îȵkãƒz†\f…ef\u0018¾Ø°îóžúO“§üÙcÆ\u0007Ý\u0011Ñ® ¿ÍlÁô|\u0006'\u0005Ù\u0003ÿ\f˜Ý\u00150\u0016\u0005F‡¥�£§‡Ý³ŠÝUŽ*ï *GÑ ?ïÿ²Ç0\u0019\u001f|YˆGB\u0011qmE„ò;¼Î»HÜq;OÇe»Ý\u0005sóÃb:\u000bñÙ\fôð0—�í\u001eÁaŽ˜\u0018ô†ÜUîªÑ…Uî\u0011îâ\u0019…\u001c·9òDQU(‡3˜\u0014œËtrÐ\u0013\u000e„2~`‹B!ûհÃKX½*Ä\u0016îl³À£\tå\\e¥Äì1î0ºŒ\u000fN\b†+ó3Â�üP†Çã.\b7Œ\u000f†\u001bò3<¡\u0010kÙ~ˆ”#®˜›Ö\u0016³�c¶õàyGÔ" },+ { "match": "—(�\u0011¦PU•asRÐë\tWVUeTq\u001emr„\u001a~\u0002\bú)\u0010h\u0003\"dØàJ\u0014ð÷`<\u001bãÁëÉ0\u0000¯Çëá8CùìÛiÜš\u0002ŽÔ\u0013òónœŠ¹¯ä^ÎýœÁó³\u0018Ýçóù‚Ï\u0000SX\u001eEÝþm¿ÎðÙ´\u001féÁ”t“vágw;�\u0014™ü¯/Vµz±Ü§ª\u0018ê´ËÜó\u0013Y„ëU\u0011+—k:å¼u¸¹79\u000e7\u001fnî•ìô8}\u001e§§X§+‹�qå\u000bU\u001bcûîüBKwì0rÐGñ¿ �n6N\u0015|osøÖq·:øXô\u001ewæÅqÆX–<êÜc\u0018\u0017,ǽÇo\u000bCAçná\u001eŸ³“£Š¥„¬^½“óØužÓËÔ»²QëÞØxõƒFÙtõ-í†Ö,훫Nö¯QùµÏøQN)”IyF\u0004;\u0019t°�\biì!“=eæð;ÏB‰\fî¤dJ7G£\u000e†\u0017‘âI±¤æåöëŸb\u0013^79\u001d”—›\u0014ÓSx;[bôéW>‹}ã¥`CÉÜ=SÕeuT¸Ï\u001d¹\u0014¶®}xÅ‹±Zõ\u0014Ë\u0017û\u0006\f|-+K\f\u0014ÉÂ*\u0002ê“ÇÊ^\bÏ7êrŽë2ÅÒž½v�F•ȷ؈ʨCÜqŽHçSž\u0011Q\"ÅG#q¥^/R¼�»ôuzúz´\u0003SC\u001fœyö\u0015õ‘8!Öß¿ôñCoââ\u001a£æ\u001aäœGqÎ\tÔŽ¼�dKu\u0012U[ë“6¦Å%Ùó‘”ò³4Ç…æ+Æ-üüB³ãl/ÑÙ’â2rìÛ§K×Ü$§CóvÖœŽ$¸zÍšêÕkÖ¬>s©å«3--8qôHÓ±cMGŽnVï«OÕ)uHøù³ÓQô4üšíÚRó95N§?n’Å,~~o¦‰Ì\t>:Fu,Æ\u000brä„Éc§ŒÈ\u001a[4^©bÑœÅóf,$ú\u0017 -\u0006ä" },+ { "match": "endstream" },+ { "match": "endobj" },+ { "match": "14 0 obj" },+ { "match": "2734" },+ { "match": "endobj" },+ { "match": "15 0 obj" },+ { "match": "(Hello)" },+ { "match": "endobj" },+ { "match": "16 0 obj" },+ { "match": "(Mac OS X 10.12.6 Quartz PDFContext)" },+ { "match": "endobj" },+ { "match": "17 0 obj" },+ { "match": "(TextEdit)" },+ { "match": "endobj" },+ { "match": "18 0 obj" },+ { "match": "(D:20200124010711Z00'00')" },+ { "match": "endobj" },+ { "match": "19 0 obj" },+ { "match": "()" },+ { "match": "endobj" },+ { "match": "20 0 obj" },+ { "match": "[ ]" },+ { "match": "endobj" },+ { "match": "1 0 obj" },+ { "match": "<< /Title 15 0 R /Producer 16 0 R /Creator 17 0 R /CreationDate 18 0 R /ModDate" },+ { "match": "18 0 R /Keywords 19 0 R /AAPL:Keywords 20 0 R >>" },+ { "match": "endobj" },+ { "match": "xref" },+ { "match": "0 21" },+ { "match": "0000000000 65535 f " },+ { "match": "0000005392 00000 n " },+ { "match": "0000000238 00000 n " },+ { "match": "0000001714 00000 n " },+ { "match": "0000000022 00000 n " },+ { "match": "0000000219 00000 n " },+ { "match": "0000000342 00000 n " },+ { "match": "0000001679 00000 n " },+ { "match": "0000001847 00000 n " },+ { "match": "0000000439 00000 n " },+ { "match": "0000001658 00000 n " },+ { "match": "0000001797 00000 n " },+ { "match": "0000002110 00000 n " },+ { "match": "0000002362 00000 n " },+ { "match": "0000005186 00000 n " },+ { "match": "0000005207 00000 n " },+ { "match": "0000005231 00000 n " },+ { "match": "0000005284 00000 n " },+ { "match": "0000005311 00000 n " },+ { "match": "0000005353 00000 n " },+ { "match": "0000005372 00000 n " },+ { "match": "trailer" },+ { "match": "<< /Size 21 /Root 11 0 R /Info 1 0 R /ID [ <8db88d3335070bd9583341583cf769a3>" },+ { "match": "<8db88d3335070bd9583341583cf769a3> ] >>" },+ { "match": "startxref" },+ { "match": "5536" },+ { "match": "%%EOF" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "#!/bin/sh" },+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[m[mecho "Hello World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[mimport java.lang.*;[m+[1;35mHello.java[m[1;36m:[m[m[m+[1;35mHello.java[m[1;36m:[m[mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m:[m[m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m[m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m:[m[m }[m+[1;35mHello.java[m[1;36m:[m[m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[m[mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[mHello[m
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m2+[1;35mHello.class[m[1;36m:[m8+[1;35mHello.java[m[1;36m:[m7+[1;35mHello.pdf[m[1;36m:[m134+[1;35mHello.sh[m[1;36m:[m2+[1;35mHello.txt[m[1;36m:[m1
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m2+[1;35mHello.class[m[1;36m:[m8+[1;35mHello.java[m[1;36m:[m7+[1;35mHello.pdf[m[1;36m:[m134+[1;35mHello.sh[m[1;36m:[m2+[1;35mHello.txt[m[1;36m:[m1
@@ -0,0 +1,6 @@+[1;35mHello.bat[m+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.sh[m+[1;35mHello.txt[m
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m:[m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "Hello World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[mimport java.lang.*;[m+[1;35mHello.java[m[1;36m:[m+[1;35mHello.java[m[1;36m:[mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m:[m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m:[m }[m+[1;35mHello.java[m[1;36m:[m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[mHello[m
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[m[mecho "Hello World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[mimport java.lang.*;[m+[1;35mHello.java[m[1;36m:[m[m[m+[1;35mHello.java[m[1;36m:[m[mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m:[m[m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m[m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m:[m[m }[m+[1;35mHello.java[m[1;36m:[m[m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[m[mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[mHello[m
tests/out/Hello_--files--bool--json.out
@@ -0,0 +1,186 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "#!/bin/sh" },+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Êþº¾\u0000\u0000\u00004\u0000\u001d" },+ { "match": "\u0000\u0006\u0000\u000f\t\u0000\u0010\u0000\u0011\b\u0000\u0012" },+ { "match": "\u0000\u0013\u0000\u0014\u0007\u0000\u0015\u0007\u0000\u0016\u0001\u0000\u0006<init>\u0001\u0000\u0003()V\u0001\u0000\u0004Code\u0001\u0000\u000fLineNumberTable\u0001\u0000\u0004main\u0001\u0000\u0016([Ljava/lang/String;)V\u0001\u0000" },+ { "match": "SourceFile\u0001\u0000" },+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" },+ { "match": "\u0000\u0000\u0000\u0006\u0000\u0001\u0000\u0000\u0000\u0003\u0000\t\u0000\u000b\u0000\f\u0000\u0001\u0000\t\u0000\u0000\u0000%\u0000\u0002\u0000\u0001\u0000\u0000\u0000\t²\u0000\u0002\u0012\u0003¶\u0000\u0004±\u0000\u0000\u0000\u0001\u0000" },+ { "match": "\u0000\u0000\u0000" },+ { "match": "\u0000\u0002\u0000\u0000\u0000\u0005\u0000\b\u0000\u0006\u0000\u0001\u0000\r\u0000\u0000\u0000\u0002\u0000\u000e" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "import java.lang.*;" },+ { "match": "" },+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": "{ public static void main(String[] arg)" },+ { "match": " { System.out.println(\"Hello World!\");" },+ { "match": " }" },+ { "match": "}" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "%PDF-1.3" },+ { "match": "%Äåòåë§ó ÐÄÆ" },+ { "match": "4 0 obj" },+ { "match": "<< /Length 5 0 R /Filter /FlateDecode >>" },+ { "match": "stream" },+ { "match": "x\u0001EŽ»" },+ { "match": "\u00021\u0014D{¿â”Z˜½‰y˜V\u0011l\u0017.ø\u0001a-d×eÍÿƒ\u0017,¬†™9\f³1²Q\u0002¹F—â©\u0012ó™�\\LY" },+ { "match": "Ÿ‰\u0007o†k÷´ŽÐ›áâj©Rj²@8þí” »¶pQ£DÄ£\rï iÂ\u000bº0¨z¬|²¿Oó¼\u001eÐ\u00177µ7ã\u0017Nÿ ¥" },+ { "match": "endstream" },+ { "match": "endobj" },+ { "match": "5 0 obj" },+ { "match": "123" },+ { "match": "endobj" },+ { "match": "2 0 obj" },+ { "match": "<< /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 612 792]" },+ { "match": ">>" },+ { "match": "endobj" },+ { "match": "6 0 obj" },+ { "match": "<< /ProcSet [ /PDF /Text ] /ColorSpace << /Cs1 7 0 R >> /Font << /TT1 8 0 R" },+ { "match": ">> >>" },+ { "match": "endobj" },+ { "match": "9 0 obj" },+ { "match": "<< /Length 10 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >>" },+ { "match": "stream" },+ { "match": "x\u0001…U]h\u001cU\u0014>»sg\u0003\u0012\u0007\u001f´\r-´ƒ?m\té2‰V\u0013‹µÛMºI\u0013·ëfS›*Êtv6;Ídfœ™Ý&¡O¥à›\u0016\u0004é« >Æ‚\b¶*6/ö¥¥Å’J5\u000f" },+ { "match": "\u0011ZŒ (}Rð;3ÛdvA2Ã�ùî¹çž{Îwî¹—¨ëoÝóì´J4ç„~¡œ›>9}JíºMiR¨›ðèFàåJ¥\tÆŽë˜üo\u001eÞ¥\u0014Kîìg[íc[öäª\u0019\u0018к†æV\u0003cŽ(¥\u0011ej†ç‡D]— \u001f<\u001bzŒo\u0003?9[)ç�×€•Ö\\@zª`:¦o\u0019jÁ×\u0017Ô’ïÖ,;éëVãlcËgÎn°¯üìFë\u000ef'Çñï…Ï\u0017Lgj\u0012x\u001fð’¡�0î\u0003¾Û´N\u0014cœN{á‘r¬ŸÎ6f§r-ùÉštª%¿PoŒ2Î\u0012¥—\u0016ë•7€Ÿ\u0000^uN\u0017�·ô×gÝq¶ÓC$õ\u0018Aþ\u0014ð³ÀZÝ\u001cã<©À\u0015ß-³>Ëê9<\u0002ü2ð%+\u001c«\u0000þôCМd9° ÅzžýÄZ\"{F?V\u0002Þ\u0006|È´\u000b¼\u0016숊\u0017–Øæ ð¼c\u0017y-Ä..›A\u0014/b\u0017?…õÊh¬/§C¿ÂsŸ&’÷Ô¬£cÀàD\u001eû£,‡?rèÙÑÞz\u0011xÉo”9ö=Àkº?R\u0000†ÍÌcU}˜y~\u0001x€N¤t2É¥Óø\u001aäпˆ7 ‹š\u0011òÈÇX\r}›" },+ { "match": "ÐpÐ|ô\fh\u0015€tZ\u0000*%´LôX'ž£R\u0015=•f¢YA„ØÊý¨oP~×§Ô€´Në�Ö�^£_\"É<ýJsèç!m`l¦Ãn\u001e^8´\b\u000fØ\u0013¶ù eÓ\u0015Û…&žG;(&Ä+bP\f‘*^\u0015‡Å!1\fé�8\u0018͉½OúÎ~>ذô.ÖMú¾\f\u000eB¬gÃ3\u0007¬p4\u0001<ø\u0007ëÎFš\t¶.îhìó¼�Þ?ï¿c\u0019·>ø³�½\u0000ú1'¿Á¢\u000bk&%æ^?÷MOÂCuE|õÖ�îëçèx2KQÞª�Y’×äûò" },+ { "match": "¾÷äÕ¤\rùgy\u0015ï½¶\\=Ê\u000bÿ“¹Í!F;’ÍAÎ<›Q´qÆ\u001bÀ!¸©Esö·YL²é¶b´`ÉB”�«¸ÿË\tóÃ<·±Rs.îð¼·?c6Í÷Š\u000f‹t¾O»¬kŸh?jh+ÚÇ@¿K\u001fJ_JßJW¤«Ò\rR¥kÒ²ô�ô½ô¹ô5z_@º,]éØIqì\u001b»\u0007~Æ{Öhí0f†³\u0014\u0010óÂÚÌ" },+ { "match": "K\u001fñw\u0006c›ù3¡Õ^\u0003�»c-刲SyF\u0019Vv+Ï)\u0013J¯r@9¬lW\u0006Ðú•Qe/Fvn°dc=΀…’g‹¦#®â<±Wu°çÃK\u001dï¦_\\ÃÖ†5ØI=\u000ežÙÚ¦\u000e¯\u0011W¿\u0015Uc¼;]œ\u0006:M!b‹Î\"r\u001f:œ\u001f'ªþÎÙ\\“85Roâ”°Ä.Ñ/ÆZ5˜\u0013\u0007P…ãmõ8ÈUš\u0019É\fgr¤fz3C™þÌ1ÆQ¬Ñù’Ù‹Ñ!|G\u0012Þ3Ë1ÿ›5Äg\u0018ï\u001dæ¨\tl£‡[+4çqß\u0011å]oÁ·fê¡: i/©9\\¯¦:æ\u0018Ù>U·m5\u001a" },+ { "match": "Tß\fL¿iV³Äw7Ï#úëõèNNm»a4üf,£Tê&Ñ·�“4" },+ { "match": "endstream" },+ { "match": "endobj" },+ { "match": "10 0 obj" },+ { "match": "1116" },+ { "match": "endobj" },+ { "match": "7 0 obj" },+ { "match": "[ /ICCBased 9 0 R ]" },+ { "match": "endobj" },+ { "match": "3 0 obj" },+ { "match": "<< /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 2 0 R ] >>" },+ { "match": "endobj" },+ { "match": "11 0 obj" },+ { "match": "<< /Type /Catalog /Pages 3 0 R >>" },+ { "match": "endobj" },+ { "match": "8 0 obj" },+ { "match": "<< /Type /Font /Subtype /TrueType /BaseFont /GQTMZF+Menlo-Regular /FontDescriptor" },+ { "match": "12 0 R /Encoding /MacRomanEncoding /FirstChar 72 /LastChar 111 /Widths [ 602" },+ { "match": "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 602 0 0 0 0 0 0 602" },+ { "match": "0 0 602 ] >>" },+ { "match": "endobj" },+ { "match": "12 0 obj" },+ { "match": "<< /Type /FontDescriptor /FontName /GQTMZF+Menlo-Regular /Flags 33 /FontBBox" },+ { "match": "[-558 -375 718 1041] /ItalicAngle 0 /Ascent 928 /Descent -236 /CapHeight 729" },+ { "match": "/StemV 99 /XHeight 547 /StemH 83 /AvgWidth 602 /MaxWidth 602 /FontFile2 13 0 R" },+ { "match": ">>" },+ { "match": "endobj" },+ { "match": "13 0 obj" },+ { "match": "<< /Length 14 0 R /Length1 4064 /Filter /FlateDecode >>" },+ { "match": "stream" },+ { "match": "x\u0001ÝW{xTÅ\u0015?sw6¯Í>’MHH€]Öå•,�„·R\u0016Hxˆ /ë.ˆòH (!\bA´1�JQ\tÁ@…\bH}\u0015Q©µ+E]\tÄT¤b#E„ \u0002" },+ { "match": "ø¢hŠ\u0014!Ø\u0000CϽ\u001bý>í×ïë¿íÜ�3çüæÌyÝ»÷Δ-\\\\DVª$P`VÉŒ\u0005d6ëI\u001eŠgÝSæ6Eн—HË�½`NITŽ‘åNsæÝ7;*'Nfy@qь¨LWxìWÌ@T\u0016}x¼®¸¤Œí\u0018Íú.\u0013×¼ÒYmó‰£\f°dƽmþé8Ëîù3JŠxäf�0é¶ tQ™)’½šÇì\u0005\u000b‹ÚôE�(¦St®�\u001a–\u0005w©Y)‹î\"\u000biä �”ÄЬ+yÖ˜×b²–>}ö�;ì7\\¤N±æâ½eéy\u0006s(¸¤ßå•W…¬�½…Åè¤1ÁëbJT\u0007\"ýàå•×’e½iɘù¾É\bÅf½®UŠ”íë¦É¡™\"…j\tL+I\u0017.RÌ'›4‰\u0003‚pš¼Ã¤vÚĈÍä\u0013·=R\u000eõ‰Dª`ÌJ>¦\t”Ë4Þ´\u0017gjÅ’�‘\u0018“·˜:Òäu\u0013‡‰h&\"\u0002!\u0005¥pµ\u0002W\u0014.+´æâŸuø®\u0002—Zªå%…K\rzËÅ�l©FK¥~ñB\u0017y1„‹\u0001ýB\u0017|{>G~ÛŠó9ø‡Â9…orqÖ…¿×¢™ClVhŽ\\;\u0018¸¦=\u0012_�)”_ÕâL!þ¦púË\fyZáË\f|¡ðù]øLáÓ:œ:™.Oµâd:NÔâ\u0013…�\u0015Ž\u001fK‘Ç\u0015Ž¥àh->ú0E~¤ðáê\u0004ùa" },+ { "match": ">¨À‘Ahb¡i\u0010\u000e+\u001cz?^\u001eRx?\u001e\u0007\u0015ÞS8På”\u00072ñ×TìWx·\u0016�«|²Qá/" },+ { "match": "ïT`ŸÂÛ" },+ { "match": "VØ»)Q¾¥°GáM…?)4°½\u0006\u0017Þ°¢~w�¬WؽkšÜ]‡Ý•ú®:ŸÜ5\r»\u0002z�\u000f;\u0015^¯E¤f¨|MáU\u001e^mÅ+lk‡Â\u001f\u000b±½\u0010/Û\u0010NÂ\u001f\u0014^R�«ø½Â‹" },+ { "match": "¿KÂ6…\u0017ž·É\u0017rñ¼\rÏmuÊçºa«\u0013ÏnñËg+°Å�ß*<£ð´ÂSO¦Ë§" },+ { "match": "ñä\u0013\u000eùd:žpà7ñجð8;y\\aS\"6nè)7*lè‰ÇØÿcµ¨]_'k\u0015Öó³µ¾\u000eë+õuk|rÝ4¬\u000bè�*üZa-Ëkë°Æ‡\u001a.FÍP<ÂÙ>âÂê\u0004T3P]ˆU\\´U>T9±Ráa…‡\u0014\u001e\\á”\u000f*¬pâW" },+ { "match": "Ë\u0015\u001ep\u000e“\u000fLÂ/\u0015*ïŲ¥\u0015r™ÂÒ" },+ { "match": "TtÄý" },+ { "match": "å6üBa‰Â=" },+ { "match": "‹Ë¬r±\u001d‹#‚\u0002Gõ2+Ê\u001aôEIX\u0014Ð\u0017*ܰ@¡tþ$YZ‹ù%ÝäüI(é†y" },+ { "match": "wåâN…¹¹(nÅœ:ÌV(R(T˜5³£œ¥0“\u001crfGÌP˜®p‡ÂíS\u0012äí6L+Ämû0•…©.LI\u0000?ÑA\u0017nUø¹Â-\u0019éò–\\LV˜¤0QaB\u0005Æ+ÜìÂ8…±Â/Ç*ÜT‡1Ýpãè4ycŒ\u001ež$G§aTAš\u001c¥0’¥‘…\u0018ÁÒˆ:\u0014¤!Ÿ�üþ\u0018>Ì)‡'axD\u000b\u0004âôaCír˜\u0013Ã\"\u001a±44`“Cí\u0018\u001a\u0011\r,\u0005†XeÀ†@DT²4Ä\u001a'‡X1$\"\u0002�Býg" },+ { "match": "ƒ9„Á¸Aáún\u0018¤0�\u000b<°\u0010\u0003z·—\u0003Æ ¿B?¿KöSè;\u0006}zµ—}Æ �‡<…\\VÌUèÍÓ½Û£W{ä0—“†žq©²g\u001düÙÉÒï‚?¢\u0019n³\u001dN™�Œl#ÜZ=«‡Of)ô`Í\u001e>t×\u0006Éî" },+ { "match": "Ý\u0014º*t±Ã—:Lú" },+ { "match": "p�\u001d^…Îv»ì¬àqû¥§\u0002n?:�AGöÜQ¡ƒB&×6S!ƒïJF:Ú+¤+¤)´c\u000bíF 5Å/S‡!Åå�)~¸\u001cHf½d\u0017’x}’‚“3w\u000eƒƒ=8œpDkg·Y¥Ý\u000e{´v¶Äxi³Â\u0016]\"×.1\u001e‰\\»\u001dº5\u000eVãÙê¯'(Äs&ñ" },+ { "match": "q©ˆu FÁ¦-" },+ { "match": "Ò\u0005prh…Æ€6\b‚\u0003\u0010~�\u0003\"\"" },+ { "match": "W¬\u0016Yÿ?�þÇSáOg„\u001a;M¬åÑØGDè!m\u0019¥¿¿\"´‡u4S/\"\u001aÅJ±“ù¼·h¤åt^ÄãmÑŸ¹z^\u001bÔ=ŒÖÐfsu\rNÓbì¢Cô\u000e\u001dcî´\u0018\b^+\u000e‘Gœ`?+ð¡¡ž¥=LËQ� è$Jh‹x‰-–SD”Ò2�Gm\"[Þ¯\u001fdt?=Ä×£´…J™72XÎñL;h\u0015] \rÚ\u0019šÂüNÚËñ(þüš¹ˆ&jaKÛ´ÁÚlÖÛËÖ6Ñ&±œšh‘Nü)WtJ6iYlu\u0007g@4“6Ë&¹Á¨\u0007�Mò\u001cÏ\u0010u°D,®\u0018/gaÔn«Ø%zkãè\u0010¯/§É¸\rwã˜X¡{õ%8C5\u001aa:ÝI\u0007d“ÅE51^ª±Ì\u0016÷éÓÍ«œ•kKôéb\u001b�a›3ñ\u001dË\u001eŽl³™1Ñ\u000em¢\u001c'Çqγ\u0019ÛlÒš(µ8h?Z¹îk5%Fé#0„ó)×o¢\rô\fÛíÊ•!*E_ö^Jåruô¢m|ùåjÔrEÍjˆ<m0mÖf‹U\u001cm\u000bW³\u0014ùÔŸ}t�gi…ØÁqSL\u0005-’M¼U$êAôZŒEêü÷¦l·#¬ùF\u0017†\u0003\u0013‚î}!�?û'¢Û\u0011ã\u000eÓøpâ}îȵkãƒz†\f…ef\u0018¾Ø°îóžúO“§üÙcÆ\u0007Ý\u0011Ñ® ¿ÍlÁô|\u0006'\u0005Ù\u0003ÿ\f˜Ý\u00150\u0016\u0005F‡¥�£§‡Ý³ŠÝUŽ*ï *GÑ ?ïÿ²Ç0\u0019\u001f|YˆGB\u0011qmE„ò;¼Î»HÜq;OÇe»Ý\u0005sóÃb:\u000bñÙ\fôð0—�í\u001eÁaŽ˜\u0018ô†ÜUîªÑ…Uî\u0011îâ\u0019…\u001c·9òDQU(‡3˜\u0014œËtrÐ\u0013\u000e„2~`‹B!ûհÃKX½*Ä\u0016îl³À£\tå\\e¥Äì1î0ºŒ\u000fN\b†+ó3Â�üP†Çã.\b7Œ\u000f†\u001bò3<¡\u0010kÙ~ˆ”#®˜›Ö\u0016³�c¶õàyGÔ" },+ { "match": "—(�\u0011¦PU•asRÐë\tWVUeTq\u001emr„\u001a~\u0002\bú)\u0010h\u0003\"dØàJ\u0014ð÷`<\u001bãÁëÉ0\u0000¯Çëá8CùìÛiÜš\u0002ŽÔ\u0013òónœŠ¹¯ä^ÎýœÁó³\u0018Ýçóù‚Ï\u0000SX\u001eEÝþm¿ÎðÙ´\u001féÁ”t“vágw;�\u0014™ü¯/Vµz±Ü§ª\u0018ê´ËÜó\u0013Y„ëU\u0011+—k:å¼u¸¹79\u000e7\u001fnî•ìô8}\u001e§§X§+‹�qå\u000bU\u001bcûîüBKwì0rÐGñ¿ �n6N\u0015|osøÖq·:øXô\u001ewæÅqÆX–<êÜc\u0018\u0017,ǽÇo\u000bCAçná\u001eŸ³“£Š¥„¬^½“óØužÓËÔ»²QëÞØxõƒFÙtõ-í†Ö,훫Nö¯QùµÏøQN)”IyF\u0004;\u0019t°�\biì!“=eæð;ÏB‰\fî¤dJ7G£\u000e†\u0017‘âI±¤æåöëŸb\u0013^79\u001d”—›\u0014ÓSx;[bôéW>‹}ã¥`CÉÜ=SÕeuT¸Ï\u001d¹\u0014¶®}xÅ‹±Zõ\u0014Ë\u0017û\u0006\f|-+K\f\u0014ÉÂ*\u0002ê“ÇÊ^\bÏ7êrŽë2ÅÒž½v�F•ȷ؈ʨCÜqŽHçSž\u0011Q\"ÅG#q¥^/R¼�»ôuzúz´\u0003SC\u001fœyö\u0015õ‘8!Öß¿ôñCoââ\u001a£æ\u001aäœGqÎ\tÔŽ¼�dKu\u0012U[ë“6¦Å%Ùó‘”ò³4Ç…æ+Æ-üüB³ãl/ÑÙ’â2rìÛ§K×Ü$§CóvÖœŽ$¸zÍšêÕkÖ¬>s©å«3--8qôHÓ±cMGŽnVï«OÕ)uHøù³ÓQô4üšíÚRó95N§?n’Å,~~o¦‰Ì\t>:Fu,Æ\u000brä„Éc§ŒÈ\u001a[4^©bÑœÅóf,$ú\u0017 -\u0006ä" },+ { "match": "endstream" },+ { "match": "endobj" },+ { "match": "14 0 obj" },+ { "match": "2734" },+ { "match": "endobj" },+ { "match": "15 0 obj" },+ { "match": "(Hello)" },+ { "match": "endobj" },+ { "match": "16 0 obj" },+ { "match": "(Mac OS X 10.12.6 Quartz PDFContext)" },+ { "match": "endobj" },+ { "match": "17 0 obj" },+ { "match": "(TextEdit)" },+ { "match": "endobj" },+ { "match": "18 0 obj" },+ { "match": "(D:20200124010711Z00'00')" },+ { "match": "endobj" },+ { "match": "19 0 obj" },+ { "match": "()" },+ { "match": "endobj" },+ { "match": "20 0 obj" },+ { "match": "[ ]" },+ { "match": "endobj" },+ { "match": "1 0 obj" },+ { "match": "<< /Title 15 0 R /Producer 16 0 R /Creator 17 0 R /CreationDate 18 0 R /ModDate" },+ { "match": "18 0 R /Keywords 19 0 R /AAPL:Keywords 20 0 R >>" },+ { "match": "endobj" },+ { "match": "xref" },+ { "match": "0 21" },+ { "match": "0000000000 65535 f " },+ { "match": "0000005392 00000 n " },+ { "match": "0000000238 00000 n " },+ { "match": "0000001714 00000 n " },+ { "match": "0000000022 00000 n " },+ { "match": "0000000219 00000 n " },+ { "match": "0000000342 00000 n " },+ { "match": "0000001679 00000 n " },+ { "match": "0000001847 00000 n " },+ { "match": "0000000439 00000 n " },+ { "match": "0000001658 00000 n " },+ { "match": "0000001797 00000 n " },+ { "match": "0000002110 00000 n " },+ { "match": "0000002362 00000 n " },+ { "match": "0000005186 00000 n " },+ { "match": "0000005207 00000 n " },+ { "match": "0000005231 00000 n " },+ { "match": "0000005284 00000 n " },+ { "match": "0000005311 00000 n " },+ { "match": "0000005353 00000 n " },+ { "match": "0000005372 00000 n " },+ { "match": "trailer" },+ { "match": "<< /Size 21 /Root 11 0 R /Info 1 0 R /ID [ <8db88d3335070bd9583341583cf769a3>" },+ { "match": "<8db88d3335070bd9583341583cf769a3> ] >>" },+ { "match": "startxref" },+ { "match": "5536" },+ { "match": "%%EOF" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "#!/bin/sh" },+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_--files--bool-C2.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[m[mecho "Hello World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[mimport java.lang.*;[m+[1;35mHello.java[m[1;36m:[m[m[m+[1;35mHello.java[m[1;36m:[m[mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m:[m[m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m[m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m:[m[m }[m+[1;35mHello.java[m[1;36m:[m[m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[m[mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[mHello[m
tests/out/Hello_--files--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m2+[1;35mHello.class[m[1;36m:[m8+[1;35mHello.java[m[1;36m:[m7+[1;35mHello.pdf[m[1;36m:[m134+[1;35mHello.sh[m[1;36m:[m2+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_--files--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m2+[1;35mHello.class[m[1;36m:[m8+[1;35mHello.java[m[1;36m:[m7+[1;35mHello.pdf[m[1;36m:[m134+[1;35mHello.sh[m[1;36m:[m2+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_--files--bool-l.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.sh[m+[1;35mHello.txt[m
tests/out/Hello_--files--bool-o.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m:[m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "Hello World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[mimport java.lang.*;[m+[1;35mHello.java[m[1;36m:[m+[1;35mHello.java[m[1;36m:[mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m:[m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m:[m }[m+[1;35mHello.java[m[1;36m:[m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[mHello[m
tests/out/Hello_--files--bool-y.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[m[mecho "Hello World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[mimport java.lang.*;[m+[1;35mHello.java[m[1;36m:[m[m[m+[1;35mHello.java[m[1;36m:[m[mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m:[m[m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m[m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m:[m[m }[m+[1;35mHello.java[m[1;36m:[m[m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[m[mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[mHello[m
tests/out/Hello_--files--bool.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[m[mecho "Hello World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[mimport java.lang.*;[m+[1;35mHello.java[m[1;36m:[m[m[m+[1;35mHello.java[m[1;36m:[m[mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m:[m[m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m[m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m:[m[m }[m+[1;35mHello.java[m[1;36m:[m[m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m[m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[m[mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[mHello[m
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m2-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m7-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m2 [1;35mHello.txt[m[1;36m:[m1
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m2-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m7-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m2 [1;35mHello.txt[m[1;36m:[m1
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m0-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m0-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m0 [1;35mHello.txt[m[1;36m:[m0
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m2-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-I-co.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m3-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-I-cv.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m5-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_Hello-World--bool--json.out
@@ -0,0 +1,14 @@+[+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-World--bool-C2.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-World--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-World--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-World--bool-l.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-World--bool-o.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-World--bool-y.out
@@ -0,0 +1,13 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m-[m[1;34mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-World--files--bool--json.out
@@ -0,0 +1,14 @@+[+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-World--files--bool-C2.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-World--files--bool-c.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-World--files--bool-co.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-World--files--bool-l.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-World--files--bool-o.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-World--files--bool-y.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-World--files--bool.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-Worldgreeting--bool--json.out
@@ -0,0 +1,20 @@+[+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-Worldgreeting--bool-C2.out
@@ -0,0 +1,7 @@+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-Worldgreeting--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m1+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-Worldgreeting--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m3+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-Worldgreeting--bool-l.out
@@ -0,0 +1,3 @@+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-Worldgreeting--bool-o.out
@@ -0,0 +1,5 @@+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;4;32mgreeting[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-Worldgreeting--bool-y.out
@@ -0,0 +1,13 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-Worldgreeting--files--bool--json.out
@@ -0,0 +1,21 @@+[+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": " { System.out.println(\"Hello World!\");" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-Worldgreeting--files--bool-C2.out
@@ -0,0 +1,9 @@+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-Worldgreeting--files--bool-c.out
@@ -0,0 +1,3 @@+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-Worldgreeting--files--bool-co.out
@@ -0,0 +1,3 @@+[1;35mHello.java[m[1;36m:[m6+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-Worldgreeting--files--bool-l.out
@@ -0,0 +1,3 @@+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-Worldgreeting--files--bool-o.out
@@ -0,0 +1,8 @@+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;4;32mWorld[m+[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mWorld[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-Worldgreeting--files--bool-y.out
@@ -0,0 +1,9 @@+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-Worldgreeting--files--bool.out
@@ -0,0 +1,4 @@+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--bool--json.out
@@ -0,0 +1,39 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": " { System.out.println(\"Hello World!\");" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-bin--bool-C2.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m1+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bin--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m3+[1;35mHello.java[m[1;36m:[m3+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bin--bool-l.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.sh[m+[1;35mHello.txt[m
tests/out/Hello_Hello-bin--bool-o.out
@@ -0,0 +1,8 @@+[1;35mHello.bat[m[1;36m:[m[1;4;32mHello[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m[1;4;32mHello[m+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--bool-y.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--bool.out
@@ -0,0 +1,7 @@+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! greeting[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--files--bool--json.out
@@ -0,0 +1,27 @@+[+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": " { System.out.println(\"Hello World!\");" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-bin--files--bool-C2.out
@@ -0,0 +1,10 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--files--bool-c.out
@@ -0,0 +1,4 @@+[1;35mHello.class[m[1;36m:[m1+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bin--files--bool-co.out
@@ -0,0 +1,4 @@+[1;35mHello.class[m[1;36m:[m3+[1;35mHello.java[m[1;36m:[m3+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bin--files--bool-l.out
@@ -0,0 +1,4 @@+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-bin--files--bool-o.out
@@ -0,0 +1,6 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--files--bool-y.out
@@ -0,0 +1,10 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bin--files--bool.out
@@ -0,0 +1,5 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! greeting[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--bool--json.out
@@ -0,0 +1,39 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": " { System.out.println(\"Hello World!\");" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-bingreeting--bool-C2.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m1+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bingreeting--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m3+[1;35mHello.java[m[1;36m:[m4+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bingreeting--bool-l.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.sh[m+[1;35mHello.txt[m
tests/out/Hello_Hello-bingreeting--bool-o.out
@@ -0,0 +1,9 @@+[1;35mHello.bat[m[1;36m:[m[1;4;32mHello[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[m[1;4;32mHello[m+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--bool-y.out
@@ -0,0 +1,14 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--bool.out
@@ -0,0 +1,7 @@+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--files--bool--json.out
@@ -0,0 +1,27 @@+[+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": " { System.out.println(\"Hello World!\");" }+ ]+ },+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-bingreeting--files--bool-C2.out
@@ -0,0 +1,10 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--files--bool-c.out
@@ -0,0 +1,4 @@+[1;35mHello.class[m[1;36m:[m1+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bingreeting--files--bool-co.out
@@ -0,0 +1,4 @@+[1;35mHello.class[m[1;36m:[m3+[1;35mHello.java[m[1;36m:[m4+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-bingreeting--files--bool-l.out
@@ -0,0 +1,4 @@+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-bingreeting--files--bool-o.out
@@ -0,0 +1,7 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--files--bool-y.out
@@ -0,0 +1,10 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-bingreeting--files--bool.out
@@ -0,0 +1,5 @@+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m World!");[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-greetingWorld--bool--json.out
@@ -0,0 +1,14 @@+[+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-greetingWorld--bool-C2.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-greetingWorld--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-greetingWorld--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-greetingWorld--bool-l.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-greetingWorld--bool-o.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-greetingWorld--bool-y.out
@@ -0,0 +1,13 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m-[m[1;34mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-greetingWorld--files--bool--json.out
@@ -0,0 +1,14 @@+[+ {+ "file": "Hello.pdf",+ "matches": [+ { "match": "(Hello)" }+ ]+ },+ {+ "file": "Hello.txt",+ "matches": [+ { "match": "Hello" }+ ]+ }+]
tests/out/Hello_Hello-greetingWorld--files--bool-C2.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-greetingWorld--files--bool-c.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-greetingWorld--files--bool-co.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m1
tests/out/Hello_Hello-greetingWorld--files--bool-l.out
@@ -0,0 +1,2 @@+[1;35mHello.pdf[m+[1;35mHello.txt[m
tests/out/Hello_Hello-greetingWorld--files--bool-o.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[1;4;32mHello[m
tests/out/Hello_Hello-greetingWorld--files--bool-y.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_Hello-greetingWorld--files--bool.out
@@ -0,0 +1,2 @@+[mBinary file[1;35m Hello.pdf[m matches+[1;35mHello.txt[m[1;36m:[m[m[1;4;32mHello[m
tests/out/Hello_HelloWorld--bool--json.out
@@ -0,0 +1,27 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": " { System.out.println(\"Hello World!\");" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ }+]
tests/out/Hello_HelloWorld--bool-C2.out
@@ -0,0 +1,12 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m
tests/out/Hello_HelloWorld--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m1+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_HelloWorld--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m2+[1;35mHello.class[m[1;36m:[m4+[1;35mHello.java[m[1;36m:[m5+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m2+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_HelloWorld--bool-l.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.sh[m
tests/out/Hello_HelloWorld--bool-o.out
@@ -0,0 +1,10 @@+[1;35mHello.bat[m[1;36m:[m[1;4;32mHello[m+[1;4;32mWorld[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;4;32mWorld[m+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mWorld[m+[1;35mHello.sh[m[1;36m:[m[1;4;32mHello[m+[1;4;32mWorld[m
tests/out/Hello_HelloWorld--bool-y.out
@@ -0,0 +1,13 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m+[1;35mHello.txt[m[1;36m-[m[1;34mHello[m
tests/out/Hello_HelloWorld--files--bool--json.out
@@ -0,0 +1,27 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ },+ {+ "file": "Hello.class",+ "matches": [+ { "match": "Hello.java\f\u0000\u0007\u0000\b\u0007\u0000\u0017\f\u0000\u0018\u0000\u0019\u0001\u0000\fHello World!\u0007\u0000\u001a\f\u0000\u001b\u0000\u001c\u0001\u0000\u0005Hello\u0001\u0000\u0010java/lang/Object\u0001\u0000\u0010java/lang/System\u0001\u0000\u0003out\u0001\u0000\u0015Ljava/io/PrintStream;\u0001\u0000\u0013java/io/PrintStream\u0001\u0000\u0007println\u0001\u0000\u0015(Ljava/lang/String;)V\u0000!\u0000\u0005\u0000\u0006\u0000\u0000\u0000\u0000\u0000\u0002\u0000\u0001\u0000\u0007\u0000\b\u0000\u0001\u0000\t\u0000\u0000\u0000\u001d\u0000\u0001\u0000\u0001\u0000\u0000\u0000\u0005*·\u0000\u0001±\u0000\u0000\u0000\u0001\u0000" }+ ]+ },+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" },+ { "match": " { System.out.println(\"Hello World!\");" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "echo \"Hello World!\"" }+ ]+ }+]
tests/out/Hello_HelloWorld--files--bool-C2.out
@@ -0,0 +1,12 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m
tests/out/Hello_HelloWorld--files--bool-c.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m1+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.sh[m[1;36m:[m1
tests/out/Hello_HelloWorld--files--bool-co.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m[1;36m:[m2+[1;35mHello.class[m[1;36m:[m4+[1;35mHello.java[m[1;36m:[m5+[1;35mHello.sh[m[1;36m:[m2
tests/out/Hello_HelloWorld--files--bool-l.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m+[1;35mHello.class[m+[1;35mHello.java[m+[1;35mHello.sh[m
tests/out/Hello_HelloWorld--files--bool-o.out
@@ -0,0 +1,10 @@+[1;35mHello.bat[m[1;36m:[m[1;4;32mHello[m+[1;4;32mWorld[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mHello[m+[1;4;32mWorld[m+[1;35mHello.java[m[1;36m:[m[1;4;32mHello[m+[1;4;32mWorld[m+[1;35mHello.sh[m[1;36m:[m[1;4;32mHello[m+[1;4;32mWorld[m
tests/out/Hello_HelloWorld--files--bool-y.out
@@ -0,0 +1,12 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m
tests/out/Hello_HelloWorld--files--bool.out
@@ -0,0 +1,5 @@+[1;35mHello.bat[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m+[mBinary file[1;35m Hello.class[m matches+[1;35mHello.java[m[1;36m:[mpublic class [m[1;4;32mHello[m // prints a [m[1;4;32mHello[m [m[1;4;32mWorld[m! greeting[m+[1;35mHello.java[m[1;36m:[m { System.out.println("[m[1;4;32mHello[m [m[1;4;32mWorld[m!");[m+[1;35mHello.sh[m[1;36m:[mecho "[m[1;4;32mHello[m [m[1;4;32mWorld[m!"[m
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m2-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m0
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m2-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m0
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m5-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_aHellogreeting--bool--json.out
@@ -0,0 +1,8 @@+[+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" }+ ]+ }+]
tests/out/Hello_aHellogreeting--bool-C2.out
@@ -0,0 +1,5 @@+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class Hello // prints [m[1;4;32ma Hello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m
tests/out/Hello_aHellogreeting--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m1+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_aHellogreeting--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m0+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m2+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m0+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_aHellogreeting--bool-l.out
@@ -0,0 +1 @@+[1;35mHello.java[m
tests/out/Hello_aHellogreeting--bool-o.out
@@ -0,0 +1,2 @@+[1;35mHello.java[m[1;36m:[m[1;4;32ma Hello[m+[1;4;32mgreeting[m
tests/out/Hello_aHellogreeting--bool-y.out
@@ -0,0 +1,12 @@+[1;35mHello.bat[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class Hello // prints [m[1;4;32ma Hello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[1;35mHello.sh[m[1;36m-[m[1;34m#!/bin/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m-[m[1;34mHello[m
tests/out/Hello_aHellogreeting--files--bool--json.out
@@ -0,0 +1,8 @@+[+ {+ "file": "Hello.java",+ "matches": [+ { "match": "public class Hello // prints a Hello World! greeting" }+ ]+ }+]
tests/out/Hello_aHellogreeting--files--bool-C2.out
@@ -0,0 +1,5 @@+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class Hello // prints [m[1;4;32ma Hello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m
tests/out/Hello_aHellogreeting--files--bool-c.out
@@ -0,0 +1 @@+[1;35mHello.java[m[1;36m:[m1
tests/out/Hello_aHellogreeting--files--bool-co.out
@@ -0,0 +1 @@+[1;35mHello.java[m[1;36m:[m2
tests/out/Hello_aHellogreeting--files--bool-l.out
@@ -0,0 +1 @@+[1;35mHello.java[m
tests/out/Hello_aHellogreeting--files--bool-o.out
@@ -0,0 +1,2 @@+[1;35mHello.java[m[1;36m:[m[1;4;32ma Hello[m+[1;4;32mgreeting[m
tests/out/Hello_aHellogreeting--files--bool-y.out
@@ -0,0 +1,7 @@+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m:[mpublic class Hello // prints [m[1;4;32ma Hello[m World! [m[1;4;32mgreeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m
tests/out/Hello_aHellogreeting--files--bool.out
@@ -0,0 +1 @@+[1;35mHello.java[m[1;36m:[mpublic class Hello // prints [m[1;4;32ma Hello[m World! [m[1;4;32mgreeting[m
tests/out/Hello_bin-Hello--bool--json.out
@@ -0,0 +1,14 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "#!/bin/sh" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "#!/bin/sh" }+ ]+ }+]
tests/out/Hello_bin-Hello--bool-C2.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m
tests/out/Hello_bin-Hello--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_bin-Hello--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_bin-Hello--bool-l.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m+[1;35mHello.sh[m
tests/out/Hello_bin-Hello--bool-o.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m[1;4;32mbin[m+[1;35mHello.sh[m[1;36m:[m[1;4;32mbin[m
tests/out/Hello_bin-Hello--bool-y.out
@@ -0,0 +1,12 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m-[m[1;34mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m-[m[1;34mHello[m
tests/out/Hello_bin-Hello--bool.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m
tests/out/Hello_bin-Hello--files--bool--json.out
@@ -0,0 +1,2 @@+[+]
tests/out/Hello_bin-Hello--files--bool-C2.out
tests/out/Hello_bin-Hello--files--bool-c.out
tests/out/Hello_bin-Hello--files--bool-co.out
tests/out/Hello_bin-Hello--files--bool-l.out
tests/out/Hello_bin-Hello--files--bool-o.out
tests/out/Hello_bin-Hello--files--bool-y.out
tests/out/Hello_bin-Hello--files--bool.out
tests/out/Hello_bin-greeting--bool--json.out
@@ -0,0 +1,14 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "#!/bin/sh" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "#!/bin/sh" }+ ]+ }+]
tests/out/Hello_bin-greeting--bool-C2.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m
tests/out/Hello_bin-greeting--bool-c.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_bin-greeting--bool-co.out
@@ -0,0 +1,6 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.class[m[1;36m:[m0+[1;35mHello.java[m[1;36m:[m0+[1;35mHello.pdf[m[1;36m:[m0+[1;35mHello.sh[m[1;36m:[m1+[1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_bin-greeting--bool-l.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m+[1;35mHello.sh[m
tests/out/Hello_bin-greeting--bool-o.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m[1;4;32mbin[m+[1;35mHello.sh[m[1;36m:[m[1;4;32mbin[m
tests/out/Hello_bin-greeting--bool-y.out
@@ -0,0 +1,12 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.java[m[1;36m-[m[1;34mimport java.lang.*;[m+[1;35mHello.java[m[1;36m-[m+[1;35mHello.java[m[1;36m-[m[1;34mpublic class Hello // prints a Hello World! greeting[m+[1;35mHello.java[m[1;36m-[m[1;34m{ public static void main(String[] arg)[m+[1;35mHello.java[m[1;36m-[m[1;34m { System.out.println("Hello World!");[m+[1;35mHello.java[m[1;36m-[m[1;34m }[m+[1;35mHello.java[m[1;36m-[m[1;34m}[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.txt[m[1;36m-[m[1;34mHello[m
tests/out/Hello_bin-greeting--bool.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m
tests/out/Hello_bin-greeting--files--bool--json.out
@@ -0,0 +1,14 @@+[+ {+ "file": "Hello.bat",+ "matches": [+ { "match": "#!/bin/sh" }+ ]+ },+ {+ "file": "Hello.sh",+ "matches": [+ { "match": "#!/bin/sh" }+ ]+ }+]
tests/out/Hello_bin-greeting--files--bool-C2.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m
tests/out/Hello_bin-greeting--files--bool-c.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m1
tests/out/Hello_bin-greeting--files--bool-co.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m1+[1;35mHello.sh[m[1;36m:[m1
tests/out/Hello_bin-greeting--files--bool-l.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m+[1;35mHello.sh[m
tests/out/Hello_bin-greeting--files--bool-o.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m[1;4;32mbin[m+[1;35mHello.sh[m[1;36m:[m[1;4;32mbin[m
tests/out/Hello_bin-greeting--files--bool-y.out
@@ -0,0 +1,4 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.bat[m[1;36m-[m[1;34mecho "Hello World!"[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m-[m[1;34mecho "Hello World!"[m
tests/out/Hello_bin-greeting--files--bool.out
@@ -0,0 +1,2 @@+[1;35mHello.bat[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m+[1;35mHello.sh[m[1;36m:[m#!/[m[1;4;32mbin[m/sh[m
tests/out/Hello_nomatch-I-c.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m0-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m0-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m0 [1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_nomatch-I-co.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m0-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m0-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m0 [1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_nomatch-I-cv.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m2-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m7-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m2 [1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_wsS-I-c.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m4-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_wsS-I-co.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m8-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m0
tests/out/Hello_wsS-I-cv.out
@@ -1,6 +1,4 @@ [1;35mHello.bat[m[1;36m:[m1-[1;35mHello.class[m[1;36m:[m0 [1;35mHello.java[m[1;36m:[m3-[1;35mHello.pdf[m[1;36m:[m0 [1;35mHello.sh[m[1;36m:[m1 [1;35mHello.txt[m[1;36m:[m0
@@ -303,12 +303,17 @@ for PAT in '' 'Hello' '\w+\s+\S+' '\S\n\S' 'nomatch' ; do fi done -for PAT in '' 'Hello World' 'Hello -World' 'Hello -World|greeting' 'Hello -(greeting|World)' '"a Hello" greeting' ; do+for PAT in '' 'Hello World' 'Hello -World' 'Hello -bin' 'bin -Hello' 'bin -greeting' 'Hello -World|greeting' 'Hello -bin|greeting' 'Hello -(greeting|World)' '"a Hello" greeting' ; do FN=`echo "Hello_$PAT" | tr -Cd '[:alnum:]_-'`- printf .- $UG -U --bool "$PAT" $FILES \- | $DIFF "out/$FN--bool.out" \- || ERR "--bool '$PAT' $FILES"+ for OPS in '' '-l' '-c' '-co' '-o' '-C2' '-y' '--json' ; do+ printf .+ $UG -U --bool $OPS "$PAT" $FILES \+ | $DIFF "out/$FN--bool$OPS.out" \+ || ERR "--bool $OPS '$PAT' $FILES"+ $UG -U --files --bool $OPS "$PAT" $FILES \+ | $DIFF "out/$FN--files--bool$OPS.out" \+ || ERR "--files --bool $OPS '$PAT' $FILES"+ done done printf .