5. EntryPoint — main.cpp
EntryPoint is the only translation unit that imports all
three library modules. main.cpp is small on purpose —
the design goal is to make the wiring itself readable: parse args,
configure Output, configure DirNav, register
two lambda callbacks, run the walk, print a summary.
5.1 Design Points
-
Module imports replace headers. The first four
lines of
main.cpp are
import cmd_line;, import dir_nav;,
import output;, and import std;. CMake's
module dependency scanner resolves build order from these imports
— no forward declarations, no include-order concerns.
-
Lambda callbacks glue
DirNav to
Output. Both callbacks capture
&out by reference and forward directly to
Output::on_dir and Output::on_file.
This is the C++ equivalent of the Rust variant's
impl DirEvent for TfAppl — a small adapter that
adapts one API to the other. Neither library imports the other,
so this glue must live in EntryPoint.
-
Help on
/h or no arguments.
argc == 1 || cl.help() short-circuits before any
configuration or traversal — help text prints, main
returns 0, no filesystem work is done.
-
Verbose block prints resolved options. When
/v is present, all seven options are printed
(including their defaults) before the walk starts. The
/p line uses
std::views::join_with(',') to reassemble the pattern
list into a single comma-separated line — a nice C++23 idiom.
-
Traversal failure is a hard error. If
dn.visit(...) returns false (path doesn't exist or
isn't a directory), main prints to
stderr and returns exit code 1. Every other error
path — regex compilation, unreadable file, permission-denied
subdir — degrades silently and the walk continues.
5.2 Startup Flow
- Construct
CmdLine cl(argc, argv) — parse argv,
apply defaults.
- If
argc == 1 or /h is present, print
help and return.
- If
/v is present, echo all resolved options.
- Construct
Output out(cl.hide()) and call
out.set_regex(cl.regex()).
- Construct
DirNav dn(cl.recurse()).
- Register two lambda callbacks that forward to
out.on_dir and out.on_file.
- Add each
/p pattern to the walker.
- Call
dn.visit(cl.path()); on failure, exit 1.
- Print the summary line (files visited / matched) and return 0.
5.3 Source — EntryPoint/src/main.cpp
import cmd_line;
import dir_nav;
import output;
import std;
int main(int argc, const char* argv[])
{
CmdLine cl(argc, argv);
// Show help when no arguments are supplied or /h is present
if (argc == 1 || cl.help())
{
std::cout << CmdLine::help_text();
return 0;
}
// Verbose: echo all options before searching
if (cl.verbose())
{
std::cout << "Options:\n"
<< " /P " << cl.path() << "\n"
<< " /r " << cl.regex() << "\n"
<< " /s " << (cl.recurse() ? "true" : "false") << "\n"
<< " /H " << (cl.hide() ? "true" : "false") << "\n";
auto patterns = cl.patterns();
if (patterns.empty())
{
std::cout << " /p (all files)\n";
}
else
{
std::cout << " /p ";
for (char c : patterns | std::views::join_with(','))
std::cout << c;
std::cout << "\n";
}
std::cout << "\n";
}
// Configure Output
Output out(cl.hide());
out.set_regex(cl.regex());
// Configure DirNav
DirNav dn(cl.recurse());
dn.set_dir_handler( [&out](const std::string& d){ out.on_dir(d); });
dn.set_file_handler([&out](const std::string& f){ out.on_file(f); });
for (const auto& pattern : cl.patterns())
dn.add_pattern(pattern);
// Run the walk
if (!dn.visit(std::filesystem::path(cl.path())))
{
std::cerr << "error: could not traverse path: " << cl.path() << "\n";
return 1;
}
// Summary
std::cout << "\n"
<< dn.file_count() << " file(s) visited, "
<< out.match_count() << " file(s) matched\n";
return 0;
}