diff --git a/applications/utilities/miscellaneous/foamToC/Make/files b/applications/utilities/miscellaneous/foamToC/Make/files
new file mode 100644
index 0000000000..8489573fc9
--- /dev/null
+++ b/applications/utilities/miscellaneous/foamToC/Make/files
@@ -0,0 +1,3 @@
+foamToC.C
+
+EXE = $(FOAM_APPBIN)/foamToC
diff --git a/applications/utilities/miscellaneous/foamToC/Make/options b/applications/utilities/miscellaneous/foamToC/Make/options
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/applications/utilities/miscellaneous/foamToC/foamToC.C b/applications/utilities/miscellaneous/foamToC/foamToC.C
new file mode 100644
index 0000000000..f58791f5e5
--- /dev/null
+++ b/applications/utilities/miscellaneous/foamToC/foamToC.C
@@ -0,0 +1,510 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration | Website: https://openfoam.org
+ \\ / A nd | Copyright (C) 2022 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Application
+ foamToC
+
+Description
+ Run-time selection table of contents printing and interrogation.
+
+ The run-time selection tables are populated by the optionally specified
+ solver class and any additional libraries listed in the \c -libs option or
+ all libraries using the \c -allLibs option. Once populated the tables can
+ be searched and printed by a range of options listed below. Table entries
+ are printed with the corresponding library they are in to aid selection
+ and the addition of \c libs entries to ensure availability to the solver.
+
+Usage
+ \b foamToC [OPTION]
+ - \par -solver \
+ Specify the solver class
+
+ - \par -libs '(\"lib1.so\" ... \"libN.so\")'
+ Specify the additional libraries to load
+
+ - \par -allLibs
+ Load all libraries
+
+ - \par switches,
+ List all available debug, info and optimisation switches
+
+ - \par all,
+ List the contents of all the run-time selection tables
+
+ - \par tables
+ List the run-time selection table names (this is the default action)
+
+ - \par table \
+ List the contents of the specified table or the list sub-tables
+
+ - \par search \
+ Search for and list the tables containing the given entry
+
+ - \par scalarBCs,
+ List scalar field boundary conditions (fvPatchField)
+
+ - \par vectorBCs,
+ List vector field boundary conditions (fvPatchField)
+
+ - \par functionObjects,
+ List functionObjects
+
+ - \par fvModels,
+ List fvModels
+
+ - \par fvConstraints,
+ List fvConstraints
+
+ Example usage:
+ - Print the list of scalar boundary conditions (fvPatchField)
+ provided by the \c fluid solver without additional libraries:
+ \verbatim
+ foamToC -solver fluid -scalarBCs
+ \endverbatim
+
+ - Print the list of RAS momentum transport models provided by the
+ \c fluid solver:
+ \verbatim
+ foamToC -solver fluid -table RAScompressibleMomentumTransportModel
+ \endverbatim
+
+ - Print the list of functionObjects provided by the
+ \c multicomponentFluid solver with the libfieldFunctionObjects.so
+ library:
+ \verbatim
+ foamToC -solver multicomponentFluid \
+ -libs '("libfieldFunctionObjects.so")' -functionObjects
+ \endverbatim
+
+ - Print a complete list of all run-time selection tables:
+ \verbatim
+ foamToC -allLibs -tables
+ or
+ foamToC -allLibs
+ \endverbatim
+
+ - Print a complete list of all entries in all run-time selection tables:
+ \verbatim
+ foamToC -allLibs -all
+ \endverbatim
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "runTimeSelectionToC.H"
+#include "dlLibraryTable.H"
+#include "HashSet.H"
+#include "IOmanip.H"
+
+using namespace Foam;
+
+// Enable run-time selection table of contents caching
+// Overrides the enableRunTimeSelectionToC = false in libOpenFOAM
+bool Foam::debug::enableRunTimeSelectionToC = true;
+
+
+HashTable> baseTypeNameToC()
+{
+ HashTable> baseTypeNameToC;
+
+ forAllConstIter
+ (
+ debug::runTimeSelectionToCType,
+ debug::runTimeSelectionToC,
+ iter
+ )
+ {
+ const word& baseType = iter.key();
+ const word& baseTypeName = iter().first();
+
+ if (!baseTypeNameToC.found(baseTypeName))
+ {
+ baseTypeNameToC.insert
+ (
+ baseTypeName,
+ HashTable()
+ );
+ }
+
+ if (!baseTypeNameToC[baseTypeName].found(baseType))
+ {
+ baseTypeNameToC[baseTypeName].insert
+ (
+ baseType,
+ iter().second()
+ );
+ }
+ }
+
+ return baseTypeNameToC;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+ entry::disableFunctionEntries = true;
+ writeInfoHeader = false;
+
+ argList::initValidTables::clear();
+
+ argList::addOption
+ (
+ "solver",
+ "name",
+ "Solver name"
+ );
+
+ argList::addOption
+ (
+ "libs",
+ "'(\"lib1.so\" ... \"libN.so\")'",
+ "Pre-load libraries"
+ );
+
+ argList::addBoolOption
+ (
+ "allLibs",
+ "Load all libraries"
+ );
+
+ argList::addBoolOption
+ (
+ "switches",
+ "List all available debug, info and optimisation switches"
+ );
+
+ argList::addBoolOption
+ (
+ "all",
+ "List the contents of all the run-time selection tables"
+ );
+
+ argList::addBoolOption
+ (
+ "tables",
+ "List the run-time selection table names"
+ );
+
+ argList::addOption
+ (
+ "table",
+ "name",
+ "List the contents of the specified table"
+ );
+
+ argList::addOption
+ (
+ "search",
+ "name",
+ "List the tables containing the given name"
+ );
+
+ argList::addBoolOption
+ (
+ "scalarBCs",
+ "List scalar field boundary conditions (fvPatchField)"
+ );
+
+ argList::addBoolOption
+ (
+ "vectorBCs",
+ "List vector field boundary conditions (fvPatchField)"
+ );
+
+ argList::addBoolOption
+ (
+ "functionObjects",
+ "List functionObjects"
+ );
+
+ argList::addBoolOption
+ (
+ "fvModels",
+ "List fvModels"
+ );
+
+ argList::addBoolOption
+ (
+ "fvConstraints",
+ "List fvConstraints"
+ );
+
+ const argList args(argc, argv);
+ if (!args.checkRootCase())
+ {
+ Foam::FatalError.exit();
+ }
+
+ word solverName;
+ if (args.optionReadIfPresent("solver", solverName))
+ {
+ libs.open("lib" + solverName + ".so");
+ }
+
+ const string libDir(getEnv("FOAM_LIBBIN"));
+ const fileNameList libNames(readDir(libDir));
+
+ if (args.optionFound("allLibs"))
+ {
+ Info << "Loading libraries:" << nl;
+ forAll(libNames, i)
+ {
+ if (libNames[i].ext() == "so")
+ {
+ Info << " " << libNames[i].c_str() << nl;
+ libs.open(libDir/libNames[i], false);
+ }
+ }
+ Info << endl;
+ }
+
+ bool done = false;
+
+ if (args.optionFound("switches"))
+ {
+ debug::listSwitches();
+ done = true;
+ }
+
+ word tableName;
+ if (args.optionReadIfPresent("table", tableName))
+ {
+ bool found = false;
+
+ if (debug::runTimeSelectionToC.found(tableName))
+ {
+ const wordList toc
+ (
+ debug::runTimeSelectionToC[tableName].second().sortedToc()
+ );
+
+ Info<< "Contents of table " << tableName
+ << ", base type "
+ << debug::runTimeSelectionToC[tableName].first()
+ << ":" << endl;
+
+ forAll(toc, i)
+ {
+ Info<< " " << setf(ios_base::left) << setw(40) << toc[i]
+ << debug::runTimeSelectionToC[tableName].second()[toc[i]]
+ << endl;
+ }
+
+ found = true;
+ }
+ else
+ {
+ const HashTable> runTimeSelectionToC
+ (
+ baseTypeNameToC()
+ );
+
+ if (runTimeSelectionToC.found(tableName))
+ {
+ const wordList toc(runTimeSelectionToC[tableName].sortedToc());
+
+ Info<< "Tables of type " << tableName << endl;
+ forAll(toc, i)
+ {
+ Info<< " " << toc[i] << endl;
+ }
+
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ Info<< "Table " << tableName << " not found" << endl;
+ }
+
+ done = true;
+ }
+
+ word name;
+ if (args.optionReadIfPresent("search", name))
+ {
+ HashTable> baseTypeNameTables;
+
+ forAllConstIter
+ (
+ debug::runTimeSelectionToCType,
+ debug::runTimeSelectionToC,
+ iter
+ )
+ {
+ const word& baseType = iter.key();
+ const word& baseTypeName = iter().first();
+
+ if (iter().second().found(name))
+ {
+ if (!baseTypeNameTables.found(baseTypeName))
+ {
+ baseTypeNameTables.insert(baseTypeName, HashTable());
+ }
+
+ baseTypeNameTables[baseTypeName].insert
+ (
+ baseType,
+ iter().second()[name]
+ );
+ }
+ }
+
+ if (baseTypeNameTables.size())
+ {
+ Info<< name << " is in tables " << endl;
+
+ const wordList toc(baseTypeNameTables.sortedToc());
+
+ forAll(toc, i)
+ {
+ if
+ (
+ baseTypeNameTables[toc[i]].size() == 1
+ && toc[i] == baseTypeNameTables[toc[i]].begin().key()
+ )
+ {
+ Info<< " " << setf(ios_base::left) << setw(40) << toc[i]
+ << baseTypeNameTables[toc[i]].begin()()
+ << endl;
+ }
+ else
+ {
+ const wordList tocc
+ (
+ baseTypeNameTables[toc[i]].sortedToc()
+ );
+
+ Info<< " " << toc[i] << endl;
+ forAll(tocc, j)
+ {
+ Info<< " "
+ << setf(ios_base::left) << setw(40) << tocc[j]
+ << baseTypeNameTables[toc[i]][tocc[j]]
+ << endl;
+ }
+ }
+ }
+ }
+ else
+ {
+ Info<< name << " not found" << endl;
+ }
+
+ done = true;
+ }
+
+ if (args.optionFound("all"))
+ {
+ Info<< "ToC:" << nl
+ << debug::runTimeSelectionToC << endl;
+ done = true;
+ }
+
+ if (args.optionFound("scalarBCs"))
+ {
+ Info<< "Scalar boundary conditions:" << nl
+ << debug::runTimeSelectionToC["fvPatchScalarField"]
+ .second().sortedToc()
+ << endl;
+ done = true;
+ }
+
+ if (args.optionFound("vectorBCs"))
+ {
+ Info<< "vector boundary conditions:" << nl
+ << debug::runTimeSelectionToC["fvPatchVectorField"]
+ .second().sortedToc()
+ << endl;
+ done = true;
+ }
+
+ if (args.optionFound("functionObjects"))
+ {
+ Info<< "functionObjects:" << nl
+ << debug::runTimeSelectionToC["functionObject"].second().sortedToc()
+ << endl;
+ done = true;
+ }
+
+ if (args.optionFound("fvModels"))
+ {
+ Info<< "fvModels:" << nl
+ << debug::runTimeSelectionToC["fvModel"].second().sortedToc()
+ << endl;
+ done = true;
+ }
+
+ if (args.optionFound("fvConstraints"))
+ {
+ Info<< "fvConstraints:" << nl
+ << debug::runTimeSelectionToC["fvConstraint"].second().sortedToc()
+ << endl;
+ done = true;
+ }
+
+ if (args.optionFound("tables") || !done)
+ {
+ const HashTable> runTimeSelectionToC
+ (
+ baseTypeNameToC()
+ );
+
+ const wordList toc(runTimeSelectionToC.sortedToc());
+
+ Info<< "Run-time selection tables:" << nl;
+
+ forAll(toc, i)
+ {
+ if
+ (
+ runTimeSelectionToC[toc[i]].size() == 1
+ && toc[i] == runTimeSelectionToC[toc[i]].begin().key()
+ )
+ {
+ Info<< " " << toc[i] << endl;
+ }
+ else
+ {
+ const wordList tocc
+ (
+ runTimeSelectionToC[toc[i]].sortedToc()
+ );
+
+ Info<< " " << toc[i] << endl;
+ forAll(tocc, j)
+ {
+ Info<< " " << tocc[j] << endl;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+// ************************************************************************* //