summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2022-04-19 11:30:47 -0400
committerTavian Barnes <tavianator@tavianator.com>2022-04-21 20:03:16 -0400
commitaa6797db463b5143c5ca05bb5e90b05d2f72122a (patch)
tree4ad640bd5d851b7c594fa2f5efaa872ceece6941 /docs
parent7f37e4131c24c08e0575db06ccf7ea986c4cc190 (diff)
downloadbfs-aa6797db463b5143c5ca05bb5e90b05d2f72122a.tar.xz
docs: Move some documentation into a subfolder
Diffstat (limited to 'docs')
-rw-r--r--docs/CHANGELOG.md655
-rw-r--r--docs/CONTRIBUTING.md167
-rw-r--r--docs/bfs.1811
3 files changed, 1633 insertions, 0 deletions
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
new file mode 100644
index 0000000..aafc497
--- /dev/null
+++ b/docs/CHANGELOG.md
@@ -0,0 +1,655 @@
+2.*
+===
+
+2.5
+---
+
+**March 27, 2022**
+
+- Added compiler-style context for errors and warnings.
+ Errors look like this:
+
+ $ bfs -nam needle
+ bfs: error: bfs -nam needle
+ bfs: error: ~~~~
+ bfs: error: Unknown argument; did you mean -name?
+
+ and warnings look like this:
+
+ $ bfs -print -name 'needle'
+ bfs: warning: bfs -print -name needle
+ bfs: warning: ~~~~~~~~~~~~
+ bfs: warning: The result of this expression is ignored.
+
+- Updated from C99 to C11
+
+- Fixed the tests when built against musl
+
+- Fixed a build error reported on Manjaro
+
+
+2.4.1
+-----
+
+**February 24, 2022**
+
+- Fixed the build when Oniguruma is not installed in the default search paths ([#82])
+
+- Fixed string encoding bugs with Oniguruma enabled
+
+- Fixed regex error reporting bugs
+
+[#82]: https://github.com/tavianator/bfs/issues/82
+
+
+2.4
+---
+
+**February 22, 2022**
+
+- Added the Oniguruma regular expression library as an (optional, but enabled by default) dependency ([#81]).
+ Oniguruma supports more regular expression syntax types than the POSIX regex API, and often performs better.
+ To build `bfs` without this new dependency, do `make WITH_ONIGURUMA=` to disable it.
+ Thanks @data-man!
+
+- Added support for the `ed`, `emacs`, `grep`, and `sed` regular expression types ([#21])
+
+- Before executing a process with `-exec[dir]`/`-ok[dir]`, `bfs` now ensures all output streams are flushed.
+ Previously, I/O from subprocesses could be interleaved unpredictably with buffered I/O from `bfs` itself.
+
+[#81]: https://github.com/tavianator/bfs/pull/81
+[#21]: https://github.com/tavianator/bfs/issues/21
+
+
+2.3.1
+-----
+
+**January 21, 2022**
+
+- Fixed the build on Debian kFreeBSD
+
+- Fixed a crash on GNU Hurd when piping bfs's output
+
+- Fixed a double-`close()` on non-Linux platforms if `fdopendir()` fails
+
+- Reduced memory allocations on startup
+
+
+2.3
+---
+
+**November 25, 2021**
+
+- More tweaks to `PAGER` and `LESS` handling for `bfs -help` ([#76])
+
+- Use 512-byte blocks for `-ls` when `POSIXLY_CORRECT` is set ([#77])
+
+- Implemented `-files0-from FILE` to take a list of `'\0'`-separated starting paths.
+ GNU find will implement the same feature in an upcoming release.
+
+- Added colors to `-printf` output ([#62])
+
+- Faster recovery from `E2BIG` during `-exec`
+
+[#76]: https://github.com/tavianator/bfs/issues/76
+[#77]: https://github.com/tavianator/bfs/issues/77
+[#62]: https://github.com/tavianator/bfs/issues/62
+
+
+2.2.1
+-----
+
+**June 2, 2021**
+
+- Fixed some incorrect coloring of broken links when links are being followed (`-L`)
+
+- Made the tests work when run as root by dropping privileges.
+ This may be helpful for certain packaging or CI environments, but is not recommended.
+
+- Treat empty `PAGER` and `LESS` environment variables like they're unset, for `bfs -help` ([#71]).
+ Thanks @markus-oberhumer!
+
+- The soft `RLIMIT_NOFILE` is now raised automatically to a fairly large value when possible.
+ This provides a minor performance benefit for large directory trees.
+
+- Implemented time units for `-mtime` as found in FreeBSD find ([#75])
+
+[#71]: https://github.com/tavianator/bfs/issues/71
+[#75]: https://github.com/tavianator/bfs/issues/75
+
+
+2.2
+---
+
+**March 6, 2021**
+
+- Fixed `-hidden` on hidden start paths
+
+- Added a Bash completion script.
+ Thanks @bmundt6!
+
+- Fixed rounding in `-used`.
+ Corresponding fixes were made to GNU find in version 4.8.0.
+
+- Optimized the open directory representation.
+ On Linux, much libc overhead is bypassed by issuing syscalls directly.
+ On all platforms, a few fewer syscalls and open file descriptors will be used.
+
+- Implemented `-flags` from BSD find
+
+
+2.1
+---
+
+**November 11, 2020**
+
+- Added a new `-status` option that displays the search progress in a bar at the bottom of the terminal
+
+- Fixed an optimizer bug introduced in version 2.0 that affected some combinations of `-user`/`-group` and `-nouser`/`-nogroup`
+
+
+2.0
+---
+
+**October 14, 2020**
+
+- [#8]: New `-exclude <expression>` syntax to more easily and reliably filter out paths.
+ For example:
+
+ bfs -name config -exclude -name .git
+
+ will find all files named `config`, without searching any directories (or files) named `.git`.
+ In this case, the same effect could have been achieved (more awkwardly) with `-prune`:
+
+ bfs ! \( -name .git -prune \) -name config
+
+ But `-exclude` will work in more cases:
+
+ # -exclude works with -depth, while -prune doesn't:
+ bfs -depth -name config -exclude -name .git
+
+ # -exclude applies even to paths below the minimum depth:
+ bfs -mindepth 3 -name config -exclude -name .git
+
+- [#30]: `-nohidden` is now equivalent to `-exclude -hidden`.
+ This changes the behavior of command lines like
+
+ bfs -type f -nohidden
+
+ to do what was intended.
+
+- Optimized the iterative deepening (`-S ids`) implementation
+
+- Added a new search strategy: exponential deepening search (`-S eds`).
+ This strategy provides many of the benefits of iterative deepening, but much faster due to fewer re-traversals.
+
+- Fixed an optimizer bug that could skip `-empty`/`-xtype` if they didn't always lead to an action
+
+- Implemented `-xattrname` to find files with a particular extended attribute (from macOS find)
+
+- Made `-printf %l` still respect the width specifier (e.g. `%10l`) for non-links, to match GNU find
+
+- Made `bfs` fail if `-color` is given explicitly and `LS_COLORS` can't be parsed, rather than falling back to non-colored output
+
+[#8]: https://github.com/tavianator/bfs/issues/8
+[#30]: https://github.com/tavianator/bfs/issues/30
+
+
+1.*
+===
+
+1.7
+---
+
+**April 22, 2020**
+
+- Fixed `-ls` printing numeric IDs instead of user/group names in large directory trees
+- Cached the user and group tables for a performance boost
+- Fixed interpretation of "default" ACLs
+- Implemented `-s` flag to sort results
+
+
+1.6
+---
+
+**February 25, 2020**
+
+- Implemented `-newerXt` (explicit reference times), `-since`, `-asince`, etc.
+- Fixed `-empty` to skip special files (pipes, devices, sockets, etc.)
+
+
+1.5.2
+-----
+
+**January 9, 2020**
+
+- Fixed the build on NetBSD
+- Added support for NFSv4 ACLs on FreeBSD
+- Added a `+` after the file mode for files with ACLs in `-ls`
+- Supported more file types (whiteouts, doors) in symbolic modes for `-ls`/`-printf %M`
+- Implemented `-xattr` on FreeBSD
+
+
+1.5.1
+-----
+
+**September 14, 2019**
+
+- Added a warning to `-mount`, since it will change behaviour in the next POSIX revision
+- Added a workaround for environments that block `statx()` with `seccomp()`, like older Docker
+- Fixed coloring of nonexistent leading directories
+- Avoided calling `stat()` on all mount points at startup
+
+
+1.5
+---
+
+**June 27, 2019**
+
+- New `-xattr` predicate to find files with extended attributes
+- Fixed the `-acl` implementation on macOS
+- Implemented depth-first (`-S dfs`) and iterative deepening search (`-S ids`)
+- Piped `-help` output into `$PAGER` by default
+- Fixed crashes on some invalid `LS_COLORS` values
+
+
+1.4.1
+-----
+
+**April 5, 2019**
+
+- Added a nicer error message when the tests are run as root
+- Fixed detection of comparison expressions with signs, to match GNU find for things like `-uid ++10`
+- Added support for https://no-color.org/
+- Decreased the number of `stat()` calls necessary in some cases
+
+
+1.4
+---
+
+**April 15, 2019**
+
+- New `-unique` option that filters out duplicate files ([#48])
+- Optimized the file coloring implementation
+- Fixed the coloring implementation to match GNU ls more closely in many corner cases
+ - Implemented escape sequence parsing for `LS_COLORS`
+ - Implemented `ln=target` for coloring links like their targets
+ - Fixed the order of fallbacks used when some color keys are unset
+- Add a workaround for incorrect file types for bind-mounted files on Linux ([#37])
+
+[#48]: https://github.com/tavianator/bfs/issues/48
+[#37]: https://github.com/tavianator/bfs/issues/37
+
+
+1.3.3
+-----
+
+**February 10, 2019**
+
+- Fixed unpredictable behaviour for empty responses to `-ok`/`-okdir` caused by an uninitialized string
+- Writing to standard output now causes `bfs` to fail if the descriptor was closed
+- Fixed incomplete file coloring in error messages
+- Added some data flow optimizations
+- Fixed `-nogroup`/`-nouser` in big directory trees
+- Added `-type w` for whiteouts, as supported by FreeBSD `find`
+- Re-wrote the `-help` message and manual page
+
+
+1.3.2
+-----
+
+**January 11, 2019**
+
+- Fixed an out-of-bounds read if LS_COLORS doesn't end with a `:`
+- Allowed multiple debug flags to be specified like `-D opt,tree`
+
+
+1.3.1
+-----
+
+**January 3, 2019**
+
+- Fixed some portability problems affecting FreeBSD
+
+
+1.3
+---
+
+**January 2, 2019**
+
+New features:
+
+- `-acl` finds files with non-trivial Access Control Lists (from FreeBSD)
+- `-capable` finds files with capabilities set
+- `-D all` turns on all debugging flags at once
+
+Fixes:
+
+- `LS_COLORS` handling has been improved:
+ - Extension colors are now case-insensitive like GNU `ls`
+ - `or` (orphan) and `mi` (missing) files are now treated differently
+ - Default colors can be unset with `di=00` or similar
+ - Specific colors fall back to more general colors when unspecified in more places
+ - `LS_COLORS` no longer needs a trailing colon
+- `-ls`/`-fls` now prints the major/minor numbers for device nodes
+- `-exec ;` is rejected rather than segfaulting
+- `bfs` now builds on old Linux versions that require `-lrt` for POSIX timers
+- For files whose access/change/modification times can't be read, `bfs` no longer fails unless those times are needed for tests
+- The testsuite is now more correct and portable
+
+
+1.2.4
+-----
+
+**September 24, 2018**
+
+- GNU find compatibility fixes for `-printf`:
+ - `%Y` now prints `?` if an error occurs resolving the link
+ - `%B` is now supported for birth/creation time (as well as `%W`/`%w`)
+ - All standard `strftime()` formats are supported, not just the ones from the GNU find manual
+- Optimizations are now re-run if any expressions are reordered
+- `-exec` and friends no longer leave zombie processes around when `exec()` fails
+
+
+1.2.3
+-----
+
+**July 15, 2018**
+
+- Fixed `test_depth_error` on filesystems that don't fill in `d_type`
+- Fixed the build on Linux architectures that don't have the `statx()` syscall (ia64, sh4)
+- Fixed use of AT_EMPTY_PATH for fstatat on systems that don't support it (Hurd)
+- Fixed `ARG_MAX` accounting on architectures with large pages (ppc64le)
+- Fixed the build against the upcoming glibc 2.28 release that includes its own `statx()` wrapper
+
+
+1.2.2
+-----
+
+**June 23, 2018**
+
+- Minor bug fixes:
+ - Fixed `-exec ... '{}' +` argument size tracking after recovering from `E2BIG`
+ - Fixed `-fstype` if `/proc` is available but `/etc/mtab` is not
+ - Fixed an uninitialized variable when given `-perm +rw...`
+ - Fixed some potential "error: 'path': Success" messages
+- Reduced reliance on GNU coreutils in the testsuite
+- Refactored and simplified the internals of `bftw()`
+
+
+1.2.1
+-----
+
+**February 8, 2018**
+
+- Performance optimizations
+
+
+1.2
+---
+
+**January 20, 2018**
+
+- Added support for the `-perm +7777` syntax deprecated by GNU find (equivalent to `-perm /7777`), for compatibility with BSD finds
+- Added support for file birth/creation times on platforms that report it
+ - `-Bmin`/`-Btime`/`-Bnewer`
+ - `B` flag for `-newerXY`
+ - `%w` and `%Wk` directives for `-printf`
+ - Uses the `statx(2)` system call on new enough Linux kernels
+- More robustness to `E2BIG` added to the `-exec` implementation
+
+
+1.1.4
+-----
+
+**October 27, 2017**
+
+- Added a man page
+- Fixed cases where multiple actions write to the same file
+- Report errors that occur when closing files/flushing streams
+- Fixed "argument list too long" errors with `-exec ... '{}' +`
+
+
+1.1.3
+-----
+
+**October 4, 2017**
+
+- Refactored the optimizer
+- Implemented data flow optimizations
+
+
+1.1.2
+-----
+
+**September 10, 2017**
+
+- Fixed `-samefile` and similar predicates when passed broken symbolic links
+- Implemented `-fstype` on Solaris
+- Fixed `-fstype` under musl
+- Implemented `-D search`
+- Implemented a cost-based optimizer
+
+
+1.1.1
+-----
+
+**August 10, 2017**
+
+- Re-licensed under the BSD Zero Clause License
+- Fixed some corner cases with `-exec` and `-ok` parsing
+
+
+1.1
+---
+
+**July 22, 2017**
+
+- Implemented some primaries from NetBSD `find`:
+ - `-exit [STATUS]` (like `-quit`, but with an optional explicit exit status)
+ - `-printx` (escape special characters for `xargs`)
+ - `-rm` (alias for `-delete`)
+- Warn if `-prune` will have no effect due to `-depth`
+- Handle y/n prompts according to the user's locale
+- Prompt the user to correct typos without having to re-run `bfs`
+- Fixed handling of paths longer than `PATH_MAX`
+- Fixed spurious "Inappropriate ioctl for device" errors when redirecting `-exec ... +` output
+- Fixed the handling of paths that treat a file as a directory (e.g. `a/b/c` where `a/b` is a regular file)
+- Fixed an expression optimizer bug that broke command lines like `bfs -name '*' -o -print`
+
+
+1.0.2
+-----
+
+**June 15, 2017**
+
+Bugfix release.
+
+- Fixed handling of \0 inside -printf format strings
+- Fixed `-perm` interpretation of permcopy actions (e.g. `u=rw,g=r`)
+
+
+1.0.1
+-----
+
+**May 17, 2017**
+
+Bugfix release.
+
+- Portability fixes that mostly affect GNU Hurd
+- Implemented `-D exec`
+- Made `-quit` not disable the implicit `-print`
+
+
+1.0
+---
+
+**April 24, 2017**
+
+This is the first release of bfs with support for all of GNU find's primitives.
+
+Changes since 0.96:
+
+- Implemented `-fstype`
+- Implemented `-exec/-execdir ... +`
+- Implemented BSD's `-X`
+- Fixed the tests under Bash 3 (mostly for macOS)
+- Some minor optimizations and fixes
+
+
+0.*
+===
+
+
+0.96
+----
+
+**March 11, 2017**
+
+73/76 GNU find features supported.
+
+- Implemented -nouser and -nogroup
+- Implemented -printf and -fprintf
+- Implemented -ls and -fls
+- Implemented -type with multiple types at once (e.g. -type f,d,l)
+- Fixed 32-bit builds
+- Fixed -lname on "symlinks" in Linux /proc
+- Fixed -quit to take effect as soon as it's reached
+- Stopped redirecting standard input from /dev/null for -ok and -okdir, as that violates POSIX
+- Many test suite improvements
+
+
+0.88
+----
+
+**December 20, 2016**
+
+67/76 GNU find features supported.
+
+- Fixed the build on macOS, and some other UNIXes
+- Implemented `-regex`, `-iregex`, `-regextype`, and BSD's `-E`
+- Implemented `-x` (same as `-mount`/`-xdev`) from BSD
+- Implemented `-mnewer` (same as `-newer`) from BSD
+- Implemented `-depth N` from BSD
+- Implemented `-sparse` from FreeBSD
+- Implemented the `T` and `P` suffices for `-size`, for BSD compatibility
+- Added support for `-gid NAME` and `-uid NAME` as in BSD
+
+
+0.84.1
+------
+
+**November 24, 2016**
+
+Bugfix release.
+
+- Fixed [#7] again
+- Like GNU find, don't print warnings by default if standard input is not a terminal
+- Redirect standard input from /dev/null for -ok and -okdir
+- Skip . when -delete'ing
+- Fixed -execdir when the root path has no slashes
+- Fixed -execdir in /
+- Support -perm +MODE for symbolic modes
+- Fixed the build on FreeBSD
+
+[#7]: https://github.com/tavianator/bfs/issues/7
+
+
+0.84
+----
+
+**October 29, 2016**
+
+64/76 GNU find features supported.
+
+- Spelling suggestion improvements
+- Handle `--`
+- (Untested) support for exotic file types like doors, ports, and whiteouts
+- Improved robustness in the face of closed std{in,out,err}
+- Fixed the build on macOS
+- Implement `-ignore_readdir_race`, `-noignore_readdir_race`
+- Implement `-perm`
+
+
+0.82
+----
+
+**September 4, 2016**
+
+62/76 GNU find features supported.
+
+- Rework optimization levels
+ - `-O1`
+ - Simple boolean simplification
+ - `-O2`
+ - Purity-based optimizations, allowing side-effect-free tests like `-name` or `-type` to be moved or removed
+ - `-O3` (**default**):
+ - Re-order tests to reduce the expected cost (TODO)
+ - `-O4`
+ - Aggressive optimizations that may have surprising effects on warning/error messages and runtime, but should not otherwise affect the results
+ - `-Ofast`:
+ - Always the highest level, currently the same as `-O4`
+- Color files with multiple hard links correctly
+- Treat `-`, `)`, and `,` as paths when required to by POSIX
+ - `)` and `,` are only supported before the expression begins
+- Implement `-D opt`
+- Implement `-D rates`
+- Implement `-fprint`
+- Implement `-fprint0`
+- Implement BSD's `-f`
+- Suggest fixes for typo'd arguments
+
+0.79
+----
+
+**May 27, 2016**
+
+60/76 GNU find features supported.
+
+- Remove an errant debug `printf()` from `-used`
+- Implement the `{} ;` variants of `-exec`, `-execdir`, `-ok`, and `-okdir`
+
+
+0.74
+----
+
+**March 12, 2016**
+
+56/76 GNU find features supported.
+
+- Color broken symlinks correctly
+- Fix [#7]
+- Fix `-daystart`'s rounding of midnight
+- Implement (most of) `-newerXY`
+- Implement `-used`
+- Implement `-size`
+
+[#7]: https://github.com/tavianator/bfs/issues/7
+
+
+0.70
+----
+
+**February 23, 2016**
+
+53/76 GNU find features supported.
+
+- New `make install` and `make uninstall` targets
+- Squelch non-positional warnings for `-follow`
+- Reduce memory footprint by as much as 64% by closing `DIR*`s earlier
+- Speed up `bfs` by ~5% by using a better FD cache eviction policy
+- Fix infinite recursion when evaluating `! expr`
+- Optimize unused pure expressions (e.g. `-empty -a -false`)
+- Optimize double-negation (e.g. `! ! -name foo`)
+- Implement `-D stat` and `-D tree`
+- Implement `-O`
+
+
+0.67
+----
+
+**February 14, 2016**
+
+Initial release.
+
+51/76 GNU find features supported.
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
new file mode 100644
index 0000000..77e8e2c
--- /dev/null
+++ b/docs/CONTRIBUTING.md
@@ -0,0 +1,167 @@
+Contributing
+============
+
+License
+-------
+
+`bfs` is licensed under the [Zero-Clause BSD License](https://opensource.org/licenses/0BSD), a maximally permissive license.
+Contributions must use the same license.
+
+
+Building
+--------
+
+`bfs` uses [GNU Make](https://www.gnu.org/software/make/) as its build system.
+A simple invocation of
+
+ $ make
+
+should build `bfs` successfully, with no additional steps necessary.
+As usual with `make`, you can run a [parallel build](https://www.gnu.org/software/make/manual/html_node/Parallel.html) with `-j`.
+For example, to use all your cores, run `make -j$(nproc)`.
+
+### Targets
+
+| Command | Description |
+|------------------|---------------------------------------------------------------|
+| `make` | Builds just the `bfs` binary |
+| `make all` | Builds everything, including the tests (but doesn't run them) |
+| `make check` | Builds everything, and runs the tests |
+| `make install` | Installs `bfs` (with man page, shell completions, etc.) |
+| `make uninstall` | Uninstalls `bfs` |
+
+### Flag-like targets
+
+The build system provides a few shorthand targets for handy configurations:
+
+| Command | Description |
+|----------------|-------------------------------------------------------------|
+| `make release` | Build `bfs` with optimizations, LTO, and without assertions |
+| `make asan` | Enable [AddressSanitizer] |
+| `make lsan` | Enable [LeakSanitizer] |
+| `make msan` | Enable [MemorySanitizer] |
+| `make tsan` | Enable [ThreadSanitizer] |
+| `make ubsan` | Enable [UndefinedBehaviorSanitizer] |
+| `make gcov` | Enable [code coverage] |
+
+[AddressSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizer
+[LeakSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#stand-alone-mode
+[MemorySanitizer]: https://github.com/google/sanitizers/wiki/MemorySanitizer
+[ThreadSanitizer]: https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual
+[UndefinedBehaviorSanitizer]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
+[code coverage]: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+
+You can combine multiple flags and other targets (e.g. `make asan ubsan check`), but not all of them will work together.
+
+### Flags
+
+Other flags are controlled with `make` variables and/or environment variables.
+Here are some of the common ones; check the [`Makefile`](/Makefile) for more.
+
+| Flag | Description |
+|----------------------------------|---------------------------------------------|
+| `CC` | The C compiler to use, e.g. `make CC=clang` |
+| `CFLAGS`<br>`EXTRA_CFLAGS` | Override/add to the default compiler flags |
+| `LDFLAGS`<br>`EXTRA_LDFLAGS` | Override/add to the linker flags |
+| `WITH_ACL`<br>`WITH_ATTR`<br>... | Enable/disable optional dependencies |
+| `TEST_FLAGS` | `tests.sh` flags for `make check` |
+| `DESTDIR` | The root directory for `make install` |
+| `PREFIX` | The installation prefix (default: `/usr`) |
+| `MANDIR` | The man page installation directory |
+
+### Dependency tracking
+
+The build system automatically tracks header dependencies with the `-M` family of compiler options (see `DEPFLAGS` in the `Makefile`).
+So if you edit a header file, `make` will rebuild the necessary object files ensuring they don't go out of sync.
+
+We go one step further than most build systems by tracking the flags that were used for the previous compilation.
+That means you can change configurations without having to `make clean`.
+For example,
+
+ $ make
+ $ make release
+
+will build the project in debug mode and then rebuild it in release mode.
+
+A side effect of this may be surprising: `make check` by itself will rebuild the project in the default configuration.
+To test a different configuration, you'll have to repeat it (e.g. `make release check`).
+
+
+Testing
+-------
+
+`bfs` comes with an extensive testsuite which can be run with
+
+ $ make check
+
+Most of the testsuite is implemented in the file [`tests.sh`](/tests.sh).
+This script contains hundreds of separate test cases.
+Most of them are *snapshot tests* which compare `bfs`'s output to a known-good copy saved under [`tests`](/tests).
+
+You can pass the name of a particular test case (or a few) to run just those tests.
+For example:
+
+ $ ./tests.sh test_basic
+
+If you need to update the reference snapshot, pass `--update`.
+It can be handy to generate the snapshot with a different `find` implementation to ensure the output is correct, for example:
+
+ $ ./tests.sh test_basic --bfs=find --update
+
+But keep in mind, other `find` implementations may not be correct.
+To my knowledge, no other implementation passes even the POSIX-compatible subset of the tests:
+
+ $ ./tests.sh --bfs=find --posix
+ ...
+ tests passed: 89
+ tests failed: 5
+
+Run
+
+ $ ./tests.sh --help
+
+for more details.
+
+### Validation
+
+A more thorough testsuite is run by the [CI](https://github.com/tavianator/bfs/actions) and to validate releases.
+It builds `bfs` in multiple configurations to test for latent bugs, memory leaks, 32-bit compatibility, etc.
+You can run it yourself with
+
+ $ make distcheck
+
+Some of these tests require `sudo`, and will prompt for your password if necessary.
+
+
+Hacking
+-------
+
+`bfs` is written in [C](https://en.wikipedia.org/wiki/C_(programming_language)), specifically [C11](https://en.wikipedia.org/wiki/C11_(C_standard_revision)).
+You can get a feel for the coding style by skimming the source code.
+[`main.c`](/src/main.c) contains an overview of the rest of source files.
+A quick summary:
+
+- Tabs for indentation, spaces for alignment.
+- Most types and functions should be namespaced with `bfs_`.
+ Exceptions are made for things that could be generally useful outside of `bfs`.
+- Error handling follows the C standard library conventions: return a nonzero `int` or a `NULL` pointer, with the error code in `errno`.
+ All failure cases should be handled, including `malloc()` failures.
+- `goto` is not harmful for cleaning up in error paths.
+
+### Adding tests
+
+Both new features and bug fixes should have associated tests.
+To add a test, create a new function in `tests.sh` called `test_<something>`.
+Snapshot tests use the `bfs_diff` function to automatically compare the generated and expected outputs.
+For example,
+
+```bash
+function test_something() {
+ bfs_diff basic -name something
+}
+```
+
+`basic` is one of the directory trees generated for test cases; others include `links`, `loops`, `deep`, and `rainbow`.
+
+Run `./tests.sh test_something --update` to generate the reference snapshot (and don't forget to `git add` it).
+Finally, add the test case to one of the arrays `posix_tests`, `bsd_tests`, `gnu_tests`, or `bfs_tests` depending on which `find` implementations it should be compatible with.
diff --git a/docs/bfs.1 b/docs/bfs.1
new file mode 100644
index 0000000..53a9831
--- /dev/null
+++ b/docs/bfs.1
@@ -0,0 +1,811 @@
+.TH BFS 1
+.SH NAME
+bfs \- breadth-first search for your files
+.SH SYNOPSIS
+.B bfs
+.RB [ flags ...]
+.RI [ paths ...]
+.RB [ expression ...]
+.PP
+flags
+.RB ( \-H / \-L / \-P
+etc.),
+.IR paths ,
+and
+.B expressions
+may be freely mixed in any order.
+.SH DESCRIPTION
+.B bfs
+is a breadth-first version of the UNIX
+.BR find (1)
+command.
+.PP
+.B bfs
+supports almost every feature from every major
+.BR find (1)
+implementation, so your existing command lines should work as-is.
+It also adds some features of its own, such as a more forgiving command line parser and some additional options.
+.PP
+Each
+.I path
+specified on the command line is treated as a starting path to search through.
+If no paths are specified, the current directory
+.RI ( . )
+is searched by default.
+.PP
+Like
+.BR find (1),
+.B bfs
+interprets its arguments as a short-circuiting Boolean expression.
+For example,
+.PP
+.nf
+.RS
+.B bfs \\\( \-name '*.txt' \-or \-lname '*.txt' \\\\) \-and \-print
+.RE
+.fi
+.PP
+will print the all the paths that are either .txt files or symbolic links to .txt files.
+.B \-and
+is implied between two consecutive expressions, so this is equivalent:
+.PP
+.nf
+.RS
+.B bfs \\\( \-name '*.txt' \-or \-lname '*.txt' \\\\) \-print
+.RE
+.fi
+.PP
+Finally,
+.B \-print
+is implied if no actions are specified, so this too is equivalent:
+.PP
+.nf
+.RS
+.B bfs \-name '*.txt' \-or \-lname '*.txt'
+.RE
+.fi
+.PP
+Most options that take a numeric argument
+.I N
+will also accept
+.I \-N
+or
+.IR +N .
+.IR \-N
+means "less than
+.IR N ,"
+and
+.I +N
+means "greater than
+.IR N ."
+.SH FLAGS
+.TP
+.B \-H
+Follow symbolic links on the command line, but not while searching.
+.TP
+.B \-L
+Follow all symbolic links.
+.TP
+.B \-P
+Never follow symbolic links (the default).
+.TP
+.B \-E
+Use extended regular expressions (same as \fB\-regextype posix-extended\fR).
+.TP
+.B \-X
+Filter out files with
+.RB non- xargs (1)-safe
+names.
+.TP
+.B \-d
+Search in post-order (same as
+.BR \-depth ).
+.TP
+.B \-s
+Visit directory entries in sorted order.
+The sorting takes place within each directory separately, which makes it different from
+.B bfs ... |
+.BR sort ,
+but still provides a deterministic ordering.
+.TP
+.B \-x
+Don't descend into other mount points (same as \fB\-xdev\fR).
+.TP
+\fB\-f \fIPATH\fR
+Treat
+.I PATH
+as a path to search (useful if it begins with a dash).
+.PP
+.TP
+\fB\-D \fIFLAG\fR
+Turn on a debugging flag (see
+.B \-D
+.IR help ).
+.PP
+\fB\-O\fIN\fR
+.RS
+Enable optimization level
+.I N
+(default:
+.IR 3 ).
+.TP
+.BI \-O 0
+Disable all optimizations.
+.TP
+.BI \-O 1
+Basic logical simplifications.
+.TP
+.BI \-O 2
+All
+.BI \-O 1
+optimizations, plus dead code elimination and data flow analysis.
+.TP
+.BI \-O 3
+All
+.BI \-O 2
+optimizations, plus re-order expressions to reduce expected cost.
+.TP
+\fB\-O\fI4\fR/\fB\-O\fIfast\fR
+All optimizations, including aggressive optimizations that may alter the observed behavior in corner cases.
+.RE
+.PP
+\fB\-S \fIbfs\fR|\fIdfs\fR|\fIids\fR|\fIeds\fR
+.RS
+Choose the search strategy.
+.TP
+.I bfs
+Breadth-first search (the default).
+.TP
+.I dfs
+Depth-first search.
+Uses less memory than breadth-first search, but is typically slower to return relevant results.
+.TP
+.I ids
+Iterative deepening search.
+Performs repeated depth-first searches with increasing depth limits.
+This gives results in the same order as breadth-first search, but with the reduced memory consumption of depth-first search.
+Tends to be very slow in practice, so use it only if you absolutely need breadth-first ordering, but
+.B \-S
+.I bfs
+consumes too much memory.
+.TP
+.I eds
+Exponential deepening search.
+A compromise between breadth- and depth-first search, which searches exponentially increasing depth ranges (e.g 0-1, 1-2, 2-4, 4-8, etc.).
+Provides many of the benefits of breadth-first search with depth-first's reduced memory consumption.
+Typically far faster than
+.B \-S
+.IR ids .
+.RE
+.SH OPERATORS
+.TP
+\fB( \fIexpression \fB)\fR
+Parentheses are used for grouping expressions together.
+You'll probably have to write
+.B \\\\(
+.I expression
+.B \\\\)
+to avoid the parentheses being interpreted by the shell.
+.PP
+\fB! \fIexpression\fR
+.br
+\fB\-not \fIexpression\fR
+.RS
+The "not" operator: returns the negation of the truth value of the
+.IR expression .
+You may have to write \fB\\! \fIexpression\fR to avoid \fB!\fR being interpreted by the shell.
+.RE
+.PP
+\fIexpression\fR \fIexpression\fR
+.br
+\fIexpression \fB\-a \fIexpression\fR
+.br
+\fIexpression \fB\-and \fIexpression\fR
+.RS
+Short-circuiting "and" operator: if the left-hand
+.I expression
+is
+.BR true ,
+returns the right-hand
+.IR expression ;
+otherwise, returns
+.BR false .
+.RE
+.PP
+\fIexpression \fB\-o \fIexpression\fR
+.br
+\fIexpression \fB\-or \fIexpression\fR
+.RS
+Short-circuiting "or" operator: if the left-hand
+.I expression
+is
+.BR false ,
+returns the right-hand
+.IR expression ;
+otherwise, returns
+.BR true .
+.RE
+.TP
+\fIexpression \fB, \fIexpression\fR
+The "comma" operator: evaluates the left-hand
+.I expression
+but discards the result, returning the right-hand
+.IR expression .
+.SH SPECIAL FORMS
+.TP
+\fB\-exclude \fIexpression\fR
+Exclude all paths matching the
+.I expression
+from the search.
+This is more powerful than
+.BR \-prune ,
+because it applies even when the expression wouldn't otherwise be evaluated, due to
+.B \-depth
+or
+.B \-mindepth
+for example.
+Exclusions are always applied before other expressions, so it may be least confusing to put them first on the command line.
+.SH OPTIONS
+.PP
+.B \-color
+.br
+.B \-nocolor
+.RS
+Turn colors on or off (default:
+.B \-color
+if outputting to a terminal,
+.B \-nocolor
+otherwise).
+.RE
+.TP
+.B \-daystart
+Measure time relative to the start of today.
+.TP
+.B \-depth
+Search in post-order (descendents first).
+.TP
+.B \-follow
+Follow all symbolic links (same as
+.BR \-L ).
+.TP
+\fB\-files0\-from \fIFILE\fR
+Treat the NUL ('\\0')-separated paths in
+.I FILE
+as starting points for the search.
+Pass
+.B \-files0\-from
+.I \-
+to read the paths from standard input.
+.PP
+\fB\-ignore_readdir_race\fR
+.br
+\fB\-noignore_readdir_race\fR
+.RS
+Whether to report an error if
+.B bfs
+detects that the file tree is modified during the search (default:
+.BR \-noignore_readdir_race ).
+.RE
+.PP
+\fB\-maxdepth \fIN\fR
+.br
+\fB\-mindepth \fIN\fR
+.RS
+Ignore files deeper/shallower than
+.IR N .
+.RE
+.TP
+.B \-mount
+Don't descend into other mount points (same as
+.B \-xdev
+for now, but will skip mount points entirely in the future).
+.TP
+.B \-nohidden
+Exclude hidden files and directories.
+.TP
+.B \-noleaf
+Ignored; for compatibility with GNU find.
+.TP
+\fB\-regextype \fITYPE\fR
+Use
+.IR TYPE -flavored
+regexes (default:
+.IR posix-basic ;
+see
+.B \-regextype
+.IR help ).
+.TP
+.B \-status
+Display a status bar while searching.
+.TP
+.B \-unique
+Skip any files that have already been seen.
+Particularly useful along with
+.BR \-L .
+.PP
+.B \-warn
+.br
+.B \-nowarn
+.RS
+Turn on or off warnings about the command line.
+.RE
+.TP
+.B \-xdev
+Don't descend into other mount points.
+.SH TESTS
+.TP
+.B \-acl
+Find files with a non-trivial Access Control List
+.RB ( acl (5)).
+.PP
+\fB\-amin\fR [\fI\-+\fR]\fIN\fR
+.br
+\fB\-Bmin\fR [\fI\-+\fR]\fIN\fR
+.br
+\fB\-cmin\fR [\fI\-+\fR]\fIN\fR
+.br
+\fB\-mmin\fR [\fI\-+\fR]\fIN\fR
+.RS
+Find files
+.BR a ccessed/ B irthed/ c hanged/ m odified
+.I N
+minutes ago.
+.RE
+.PP
+\fB\-anewer \fIFILE\fR
+.br
+\fB\-Bnewer \fIFILE\fR
+.br
+\fB\-cnewer \fIFILE\fR
+.br
+\fB\-mnewer \fIFILE\fR
+.RS
+Find files
+.BR a ccessed/ B irthed/ c hanged/ m odified
+more recently than
+.I FILE
+was modified.
+.RE
+.PP
+\fB\-asince \fITIME\fR
+.br
+\fB\-Bsince \fITIME\fR
+.br
+\fB\-csince \fITIME\fR
+.br
+\fB\-msince \fITIME\fR
+.RS
+Find files
+.BR a ccessed/ B irthed/ c hanged/ m odified
+more recently than the ISO 8601-style timestamp
+.IR TIME .
+See
+.BI \-newer XY
+for examples of the timestamp format.
+.RE
+.PP
+\fB\-atime\fR [\fI\-+\fR]\fIN\fR
+.br
+\fB\-Btime\fR [\fI\-+\fR]\fIN\fR
+.br
+\fB\-ctime\fR [\fI\-+\fR]\fIN\fR
+.br
+\fB\-mtime\fR [\fI\-+\fR]\fIN\fR
+.RS
+Find files
+.BR a ccessed/ B irthed/ c hanged/ m odified
+.I N
+days ago.
+.RE
+.TP
+.B \-capable
+Find files with POSIX.1e
+.BR capabilities (7)
+set.
+.TP
+\fB\-depth\fR [\fI\-+\fR]\fIN\fR
+Find files with depth
+.IR N .
+.TP
+.B \-empty
+Find empty files/directories.
+.PP
+.B \-executable
+.br
+.B \-readable
+.br
+.B \-writable
+.RS
+Find files the current user can execute/read/write.
+.RE
+.PP
+.B \-false
+.br
+.B \-true
+.RS
+Always false/true.
+.RE
+.TP
+.B \-fstype TYPE
+Find files on file systems with the given
+.BR TYPE .
+.PP
+\fB\-gid\fR [\fI\-+\fR]\fIN\fR
+.br
+\fB\-uid\fR [\fI\-+\fR]\fIN\fR
+.RS
+Find files owned by group/user ID
+.IR N .
+.RE
+.PP
+\fB\-group \fINAME\fR
+.br
+\fB\-user \fINAME\fR
+.RS
+Find files owned by the group/user
+.IR NAME .
+.RE
+.TP
+.B \-hidden
+Find hidden files (those beginning with
+.IR . ).
+.PP
+\fB\-ilname \fIGLOB\fR
+.br
+\fB\-iname \fIGLOB\fR
+.br
+\fB\-ipath \fIGLOB\fR
+.br
+\fB\-iregex \fIREGEX\fR
+.br
+\fB\-iwholename \fIGLOB\fR
+.RS
+Case-insensitive versions of
+.BR \-lname / \-name / \-path / \-regex / \-wholename .
+.RE
+.TP
+\fB\-inum\fR [\fI\-+\fR]\fIN\fR
+Find files with inode number
+.IR N .
+.TP
+\fB\-links\fR [\fI\-+\fR]\fIN\fR
+Find files with
+.I N
+hard links.
+.TP
+\fB\-lname \fIGLOB\fR
+Find symbolic links whose target matches the
+.IR GLOB .
+.TP
+\fB\-name \fIGLOB\fR
+Find files whose name matches the
+.IR GLOB .
+.TP
+\fB\-newer \fIFILE\fR
+Find files newer than
+.IR FILE .
+.TP
+\fB\-newer\fIXY \fIREFERENCE\fR
+Find files whose
+.I X
+time is newer than the
+.I Y
+time of
+.IR REFERENCE .
+.I X
+and
+.I Y
+can be any of
+.RI [ aBcm ]
+.RI ( a ccess/ B irth/ c hange/ m odification).
+.I Y
+may also be
+.I t
+to parse
+.I REFERENCE
+as an ISO 8601-style timestamp. For example:
+.PP
+.RS
+1991-12-14
+.br
+1991-12-14T03:00
+.br
+1991-12-14T03:00-07:00
+.br
+1991-12-14T10:00Z
+.RE
+.PP
+.B \-nogroup
+.br
+.B \-nouser
+.RS
+Find files owned by nonexistent groups/users.
+.RE
+.PP
+\fB\-path \fIGLOB\fR
+.br
+\fB\-wholename \fIGLOB\fR
+.RS
+Find files whose entire path matches the
+.IR GLOB .
+.RE
+.TP
+\fB\-perm\fR [\fI\-\fR]\fIMODE\fR
+Find files with a matching mode.
+.TP
+\fB\-regex \fIREGEX\fR
+Find files whose entire path matches the regular expression
+.IR REGEX .
+.TP
+\fB\-samefile \fIFILE\fR
+Find hard links to
+.IR FILE .
+.TP
+\fB\-since \fITIME\fR
+Find files modified since the ISO 8601-style timestamp
+.IR TIME .
+See
+.BI \-newer XY
+for examples of the timestamp format.
+.TP
+\fB\-size\fR [\fI\-+\fR]\fIN\fR[\fIcwbkMGTP\fR]
+Find files with the given size, in 1-byte
+.IR c haracters,
+2-byte
+.IR w ords,
+512-byte
+.IR b locks
+(default), or
+.IR k iB/ M iB/ G iB/ T iB/ P iB.
+.TP
+.B \-sparse
+Find files that occupy fewer disk blocks than expected.
+.TP
+\fB\-type\fR [\fIbcdlpfswD\fR]
+Find files of the given type.
+Possible types are
+.IR b lock
+device,
+.IR c haracter
+device,
+.IR d irectory,
+symbolic
+.IR l ink,
+.IR p ipe,
+regular
+.IR f ile,
+.IR s ocket,
+.IR w hiteout,
+and
+.IR D oor.
+.TP
+\fB\-used\fR [\fI\-+\fR]\fIN\fR
+Find files last accessed
+.I N
+days after they were changed.
+.TP
+.B \-xattr
+Find files with extended attributes
+.RB ( xattr (7)).
+.TP
+\fB\-xattrname\fR \fINAME\fR
+Find files with the extended attribute
+.IR NAME .
+.TP
+\fB\-xtype\fR [\fIbcdlpfswD\fR]
+Find files of the given type, following links when
+.B \-type
+would not, and vice versa.
+.SH ACTIONS
+.PP
+.B \-delete
+.br
+.B \-rm
+.RS
+Delete any found files (implies \fB-depth\fR).
+.RE
+.TP
+\fB\-exec \fIcommand ... {} ;\fR
+Execute a command.
+.TP
+\fB\-exec \fIcommand ... {} +\fR
+Execute a command with multiple files at once.
+.TP
+\fB\-ok \fIcommand ... {} ;\fR
+Prompt the user whether to execute a command.
+.PP
+\fB\-execdir \fIcommand ... {} ;\fR
+.br
+\fB\-execdir \fIcommand ... {} +\fR
+.br
+\fB\-okdir \fIcommand ... {} ;\fR
+.RS
+Like
+.BR \-exec / \-ok ,
+but run the command in the same directory as the found file(s).
+.RE
+.TP
+\fB\-exit\fR [\fISTATUS\fR]
+Exit immediately with the given status (0 if unspecified).
+.PP
+\fB\-fls \fIFILE\fR
+.br
+\fB\-fprint \fIFILE\fR
+.br
+\fB\-fprint0 \fIFILE\fR
+.br
+\fB\-fprintf \fIFILE FORMAT\fR
+.RS
+Like
+.BR \-ls / \-print / \-print0 / \-printf ,
+but write to
+.I FILE
+instead of standard output.
+.RE
+.TP
+.B \-ls
+List files like
+.B ls
+.IR \-dils .
+.TP
+.B \-print
+Print the path to the found file.
+.TP
+.B \-print0
+Like
+.BR \-print ,
+but use the null character ('\\0') as a separator rather than newlines.
+Useful in conjunction with
+.B xargs
+.IR \-0 .
+.TP
+\fB\-printf \fIFORMAT\fR
+Print according to a format string (see
+.BR find (1)).
+These additional format directives are supported:
+.RS
+.TP
+%w
+The file's birth time, in the same format as %a/%c/%t.
+.TP
+.RI %W k
+Field
+.I k
+of the file's birth time, in the same format as
+.RI %A k /%C k /%T k .
+.RE
+.TP
+.B \-printx
+Like
+.BR \-print ,
+but escape whitespace and quotation characters, to make the output safe for
+.BR xargs (1).
+Consider using
+.B \-print0
+and
+.B xargs
+.I \-0
+instead.
+.TP
+.B \-prune
+Don't descend into this directory.
+.TP
+.B \-quit
+Quit immediately.
+.TP
+.B \-version
+Print version information.
+.TP
+.B \-help
+Print usage information.
+.SH ENVIRONMENT
+Certain environment variables affect the behavior of
+.BR bfs .
+.PP
+.B LANG
+.br
+.B LC_*
+.RS
+Specifies the
+.BR locale (7)
+in use for various things.
+.B bfs
+is not (yet) translated to any languages except English, but the locale will still affect the format of printed values.
+Yes/no prompts (e.g. from
+.BR \-ok )
+will also be interpreted according to the current locale.
+.RE
+.PP
+.B LS_COLORS
+.br
+.B BFS_COLORS
+.RS
+Controls the colors used when displaying file paths if
+.B \-color
+is enabled.
+.B bfs
+interprets
+.B LS_COLORS
+the same way GNU
+.BR ls (1)
+does (see
+.BR dir_colors (5)).
+.B BFS_COLORS
+can be used to customize
+.B bfs
+without affecting other commands.
+.RE
+.TP
+.B NO_COLOR
+Causes
+.B bfs
+to default to
+.B \-nocolor
+if it is set (see https://no-color.org/).
+.TP
+.B PAGER
+Specifies the pager used for
+.B \-help
+output.
+Defaults to
+.BR more (1).
+.TP
+.B POSIXLY_CORRECT
+Makes
+.B bfs
+conform more strictly to the POSIX.1-2017 specification for
+.BR find (1).
+Currently this just disables warnings by default.
+It does not disable
+.BR bfs 's
+various extensions to the base POSIX functionality.
+.SH EXAMPLES
+.TP
+.B bfs
+With no arguments,
+.B bfs
+prints all files under the current directory in breadth-first order.
+.TP
+.B bfs \-name '*.txt'
+Prints all the .txt files under the current directory.
+.B *.txt
+is quoted to ensure the glob is processed by
+.B bfs
+rather than the shell.
+.TP
+\fBbfs \-name access_log \-L \fI/var\fR
+Finds all files named
+.B access_log
+under
+.IR /var ,
+following symbolic links.
+.B bfs
+allows flags and paths to appear anywhere on the command line.
+.TP
+\fBbfs \fI~ \fB\-not \-user $USER\fR
+Prints all files in your home directory not owned by you.
+.TP
+.B bfs \-xtype l
+Finds broken symbolic links.
+.TP
+.B bfs \-name config \-exclude \-name .git
+Finds all files named
+.BR config,
+skipping every
+.B .git
+directory.
+.TP
+.B bfs \-type f \-executable \-exec strip '{}' +
+Runs
+.BR strip (1)
+on all executable files it finds, passing it multiple files at a time.
+.SH BUGS
+https://github.com/tavianator/bfs/issues
+.SH AUTHOR
+Tavian Barnes <tavianator@tavianator.com>
+.PP
+https://tavianator.com/projects/bfs.html
+.SH SEE ALSO
+.BR find (1),
+.BR locate (1),
+.BR xargs (1)