diff --git a/applications/test/etcFiles/Test-etcFiles.C b/applications/test/etcFiles/Test-etcFiles.C index 59d3a8b47f0b6c9cd2a903e80469f9e41c552cbb..41958ac33f808301a4204f2f1d185bcb1bc9d199 100644 --- a/applications/test/etcFiles/Test-etcFiles.C +++ b/applications/test/etcFiles/Test-etcFiles.C @@ -102,6 +102,12 @@ int main(int argc, char *argv[]) } } + + // This should and will fail: + //// Info<<"find bad file:" << nl + //// << findEtcFile("##BadName##", true) << "FAIL" << endl; + + const bool listAll = (args.found("all") || args.found("list")); int error = 0; diff --git a/applications/test/string/Test-string.C b/applications/test/string/Test-string.C index 52d2b58ab239bc7e611a665184b55a1da6314120..6f06ddd11a18929bb7f0a98db2cab5b80c1f4634 100644 --- a/applications/test/string/Test-string.C +++ b/applications/test/string/Test-string.C @@ -102,6 +102,13 @@ int main(int argc, char *argv[]) : { "~OpenFOAM/controlDict", "<etc>/controlDict", + "<etc:ugo>/controlDict", + "<etc:u>/controlDict", + "<etc:ug>/controlDict", + "<etc:go>/controlDict", + "<etc:o>/controlDict", + "<etc:JUNK>/controlDict", // rubbish input + "<etc:>/controlDict", // rubbish input "$FOAM_CASE/xyz", "<case>/xyz", "$FOAM_CASE/constant/xyz", "<constant>/xyz", "$FOAM_CASE/system/xyz", "<system>/xyz", diff --git a/applications/utilities/preProcessing/createZeroDirectory/createZeroDirectory.C b/applications/utilities/preProcessing/createZeroDirectory/createZeroDirectory.C index 68b7e607a98f76c2ffc98f47594379bff77a03cc..e492bd37fffbb8536d481c11d729900a2d277ac0 100644 --- a/applications/utilities/preProcessing/createZeroDirectory/createZeroDirectory.C +++ b/applications/utilities/preProcessing/createZeroDirectory/createZeroDirectory.C @@ -240,12 +240,13 @@ int main(int argc, char *argv[]) fileName baseDir ( - "${WM_PROJECT_DIR}/etc/caseDicts/createZeroDirectoryTemplates" + args.opt<fileName> + ( + "templateDir", + // Default is from PROJECT/etc directory + "<etc:o>/caseDicts/createZeroDirectoryTemplates" + ) ); - if (args.found("templateDir")) - { - baseDir = args["templateDir"]; - } baseDir.expand(); baseDir.toAbsolute(); diff --git a/src/OpenFOAM/global/etcFiles/etcFiles.C b/src/OpenFOAM/global/etcFiles/etcFiles.C index fc9997b4bf956263421c65a97eafc47a924ec414..2b941f5fc3cb09df03a9cd81b31843e29551659f 100644 --- a/src/OpenFOAM/global/etcFiles/etcFiles.C +++ b/src/OpenFOAM/global/etcFiles/etcFiles.C @@ -30,12 +30,32 @@ License // * * * * * * * * * * * * * * Static Functions * * * * * * * * * * * * * * // // -// These could be exposed too (if required), but are fairly special purpose. +// Some of these could be exposed too (if required), +// but are fairly special purpose. // namespace { +// Return the file location mode as a string. +// +// - u : location mask 0700 +// - g : location mask 0070 +// - o : location mask 0007 +// +static inline std::string locationToString(unsigned short location) +{ + std::string mode; + + if (location & 0700) { mode += 'u'; } // User + if (location & 0070) { mode += 'g'; } // Group + if (location & 0007) { mode += 'o'; } // Other + if (mode.empty()) { mode = "???"; } + + return mode; +} + + // Assign 'queried' parameter to the user resource directory. // Return true if this directory exists. // @@ -64,6 +84,7 @@ static inline bool userResourceDir(Foam::fileName& queried) // Assign 'queried' parameter to the group resource directory. // Return true if this directory exists. +// Otherwise clears the parameter and returns false. // // Corresponds to foamEtcFile -mode=g // Looks for @@ -102,6 +123,7 @@ static inline bool groupResourceDir(Foam::fileName& queried) // Assign 'queried' parameter to the OpenFOAM etc/ resource directory. // Return true if it exists. +// Otherwise clears the parameter and returns false. // // Corresponds to foamEtcFile -mode=o // Looks for @@ -122,6 +144,7 @@ static inline bool projectResourceDir(Foam::fileName& queried) Foam::fileNameList searchEtc ( const Foam::fileName& name, + unsigned short location, const bool findFirst, bool (*accept)(const Foam::fileName&) ) @@ -131,13 +154,23 @@ Foam::fileNameList searchEtc const Foam::fileName version(std::to_string(Foam::foamVersion::api)); Foam::fileNameList list; - Foam::fileName dir, candidate; + Foam::fileName queried, candidate; + + if (!(location & 0777)) + { + // Warn about bad location (mode) ... or make it FATAL? + std::cerr + << "--> FOAM Error :\n " + "No user/group/other location specified for 'etc' file" + " or directory\n '" + << name.c_str() << "'\n\n" << std::endl; + } // User resource directories - if (userResourceDir(dir)) + if ((location & 0700) && userResourceDir(queried)) { - candidate = dir/version/name; + candidate = queried/version/name; if (accept(candidate)) { list.append(std::move(candidate)); @@ -147,7 +180,7 @@ Foam::fileNameList searchEtc } } - candidate = dir/name; + candidate = queried/name; if (accept(candidate)) { list.append(std::move(candidate)); @@ -159,9 +192,9 @@ Foam::fileNameList searchEtc } // Group (site) resource directories - if (groupResourceDir(dir)) + if ((location & 0070) && groupResourceDir(queried)) { - candidate = dir/version/name; + candidate = queried/version/name; if (accept(candidate)) { list.append(std::move(candidate)); @@ -171,7 +204,7 @@ Foam::fileNameList searchEtc } } - candidate = dir/name; + candidate = queried/name; if (accept(candidate)) { list.append(std::move(candidate)); @@ -183,9 +216,9 @@ Foam::fileNameList searchEtc } // Other (project) resource directory - if (projectResourceDir(dir)) + if ((location & 0007) && projectResourceDir(queried)) { - candidate = dir/name; + candidate = queried/name; if (accept(candidate)) { list.append(std::move(candidate)); @@ -207,27 +240,27 @@ Foam::fileNameList Foam::etcDirs(bool test) const Foam::fileName version(std::to_string(Foam::foamVersion::api)); Foam::fileNameList list(5); - Foam::fileName dir; + Foam::fileName queried; label nDirs = 0; // User resource directories - if (userResourceDir(dir) || (!test && dir.size())) + if (userResourceDir(queried) || (!test && queried.size())) { - list[nDirs++] = dir/version; - list[nDirs++] = dir; + list[nDirs++] = queried/version; + list[nDirs++] = queried; } // Group (site) resource directories - if (groupResourceDir(dir) || (!test && dir.size())) + if (groupResourceDir(queried) || (!test && queried.size())) { - list[nDirs++] = dir/version; - list[nDirs++] = dir; + list[nDirs++] = queried/version; + list[nDirs++] = queried; } // Other (project) resource directory - if (projectResourceDir(dir) || (!test && dir.size())) + if (projectResourceDir(queried) || (!test && queried.size())) { - list[nDirs++] = dir; + list[nDirs++] = queried; } list.resize(nDirs); @@ -239,13 +272,15 @@ Foam::fileNameList Foam::etcDirs(bool test) Foam::fileNameList Foam::findEtcDirs ( const fileName& name, - const bool findFirst + const bool findFirst, + unsigned short location ) { return searchEtc ( name, + location, findFirst, [](const fileName& f){ return Foam::isDir(f); } ); @@ -256,7 +291,8 @@ Foam::fileNameList Foam::findEtcFiles ( const fileName& name, const bool mandatory, - const bool findFirst + const bool findFirst, + unsigned short location ) { fileNameList list; @@ -267,6 +303,7 @@ Foam::fileNameList Foam::findEtcFiles list = searchEtc ( name, + location, findFirst, [](const fileName& f){ return Foam::isFile(f); } ); @@ -274,11 +311,16 @@ Foam::fileNameList Foam::findEtcFiles if (mandatory && list.empty()) { - // Abort if file is mandatory but not found + // Abort if file is mandatory but not found. + // Use a direct exit, since this could occur before anything is + // setup at all. + std::cerr - << "--> FOAM FATAL ERROR in Foam::findEtcFiles()" - " : could not find mandatory file\n '" - << name.c_str() << "'\n\n" << std::endl; + << "--> FOAM FATAL ERROR :\n " + "Could not find mandatory etc file (mode=" + << locationToString(location) << ")\n '" + << name.c_str() << "'\n" + << std::endl; ::exit(1); } @@ -286,16 +328,42 @@ Foam::fileNameList Foam::findEtcFiles } -Foam::fileName Foam::findEtcFile(const fileName& name, const bool mandatory) +Foam::fileName Foam::findEtcDir +( + const fileName& name, + unsigned short location +) { - fileNameList list(findEtcFiles(name, mandatory, true)); + fileNameList list(findEtcDirs(name, true, location)); + + fileName found; + + if (list.size()) + { + found = std::move(list.first()); + } + + return found; +} + + +Foam::fileName Foam::findEtcFile +( + const fileName& name, + const bool mandatory, + unsigned short location +) +{ + fileNameList list(findEtcFiles(name, mandatory, true, location)); + + fileName found; if (list.size()) { - return list.first(); + found = std::move(list.first()); } - return fileName(); + return found; } diff --git a/src/OpenFOAM/global/etcFiles/etcFiles.H b/src/OpenFOAM/global/etcFiles/etcFiles.H index 9fdcc696c330cdbee8fa666287f5d8e79f46cf8f..7143756441b8a5c815f17c9e39f555d46a42e232 100644 --- a/src/OpenFOAM/global/etcFiles/etcFiles.H +++ b/src/OpenFOAM/global/etcFiles/etcFiles.H @@ -60,25 +60,38 @@ fileNameList etcDirs(bool test=true); fileNameList findEtcDirs ( const fileName& name, //!< The directory to search for - const bool findFirst=false //!< Stop after locating the first directory + const bool findFirst=false, //!< Stop after locating the first directory + unsigned short location=0777 //!< User/group/other location ); +//- Search for a single directory using findEtcDirs(). +// +// \return The full path name of the first directory found in the +// search hierarchy or an empty fileName if the name cannot be found. +fileName findEtcDir +( + const fileName& name, //!< The directory to search for + unsigned short location=0777 //!< User/group/other location +); + //- Search for files from user/group/other directories. // -// The search hierarchy corresponds to that of the foamEtcFile script, -// which allows for version-specific and version-independent files: -// -# \b user settings +// The search hierarchy corresponds to that of the \c foamEtcFile script, +// which allows for version-specific and version-independent files. +// +// -# \b user settings (\c location=0700) // - ~/.OpenFOAM/{PROJECT_API} // - ~/.OpenFOAM/ -// -# \b group settings +// -# \b group settings (\c location=0070) // - $WM_PROJECT_SITE/{PROJECT_API}/etc/ // - $WM_PROJECT_SITE/etc/ -// -# \b other (shipped) settings +// -# \b other (shipped) settings (\c location=0007) // - $WM_PROJECT_DIR/etc/ // -// Where {PROJECT_API} is the value of the OPENFOAM define. -// - \b \$WM_PROJECT_SITE : If unset, uses $WM_PROJECT_DIR/site +// Where {PROJECT_API} corresponds to the foamVersion::api value. +// +// \note When \c \$WM_PROJECT_SITE is unset, uses \c $WM_PROJECT_DIR/site // // \return The list of full paths of all the matching files or // an empty list if the name cannot be found. @@ -86,7 +99,8 @@ fileNameList findEtcFiles ( const fileName& name, //!< The file to search for const bool mandatory=false, //!< Abort if the file cannot be found - const bool findFirst=false //!< Stop after locating the first directory + const bool findFirst=false, //!< Stop after locating the first directory + unsigned short location=0777 //!< User/group/other location ); @@ -97,7 +111,8 @@ fileNameList findEtcFiles fileName findEtcFile ( const fileName& name, //!< The file to search for - const bool mandatory=false //!< Abort if the file cannot be found + const bool mandatory=false, //!< Abort if the file cannot be found + unsigned short location=0777 //!< User/group/other location ); diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.C b/src/OpenFOAM/primitives/strings/stringOps/stringOps.C index 0d86363d3f9b0f0ab2d2b444963c15018110904f..eaf82965124285bfa3fb85bc2145e5ad04d2ef8f 100644 --- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.C +++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.C @@ -37,10 +37,33 @@ License namespace Foam { +// Return the file location mode (string) as a numerical value. +// +// - u : location mask 0700 +// - g : location mask 0070 +// - o : location mask 0007 +// +static inline unsigned short modeToLocation +( + const std::string& mode, + std::size_t pos = 0 +) +{ + unsigned short where(0); + + if (std::string::npos != mode.find('u', pos)) { where |= 0700; } // User + if (std::string::npos != mode.find('g', pos)) { where |= 0070; } // Group + if (std::string::npos != mode.find('o', pos)) { where |= 0007; } // Other + + return where; +} + + // Expand a leading <tag>/ // Convenient for frequently used directories // -// <etc>/ => user/group/other OpenFOAM directory +// <etc>/ => user/group/other etc - findEtcFile() +// <etc(:[ugo]+)?>/ => user/group/other etc - findEtcFile() // <case>/ => FOAM_CASE directory // <constant>/ => FOAM_CASE/constant directory // <system>/ => FOAM_CASE/system directory @@ -52,7 +75,7 @@ static void expandLeadingTag(std::string& s, const char b, const char e) } auto delim = s.find(e); - if (delim == std::string::npos) + if (std::string::npos == delim) { return; // Error: no closing delim - ignore expansion } @@ -73,6 +96,7 @@ static void expandLeadingTag(std::string& s, const char b, const char e) } const std::string tag(s, 1, delim-2); + const auto tagLen = tag.length(); // Note that file is also allowed to be an empty string. @@ -88,6 +112,12 @@ static void expandLeadingTag(std::string& s, const char b, const char e) { s = fileName(Foam::getEnv("FOAM_CASE"))/tag/file; } + else if (tagLen >= 4 && tag.compare(0, 4, "etc:") == 0) + { + // <etc:ugo> type of tag - convert "ugo" to numeric + + s = findEtcFile(file, false, modeToLocation(tag, 4)); + } } diff --git a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H index 6e965085fa3ae669680cfae1294342b8742af509..74d11b051b7fa90d50aee476c7bdd6c52527238e 100644 --- a/src/OpenFOAM/primitives/strings/stringOps/stringOps.H +++ b/src/OpenFOAM/primitives/strings/stringOps/stringOps.H @@ -219,30 +219,45 @@ namespace stringOps // -# environment variables // - "$VAR", "${VAR}" // -# current directory - // - leading "./" : the current directory + // - leading "./" + // : the current directory - Foam::cwd() // -# leading tag expansion for commonly used directories - // - \<etc\>/ : user/group/other OpenFOAM directory - // - \<case\>/ : FOAM_CASE directory - // - \<constant\>/ : FOAM_CASE/constant directory - // - \<system\>/ : FOAM_CASE/system directory + // - <b> \<etc\>/ </b> + // : user/group/other OpenFOAM etc directory + // - <b> \<etc:</b><em>[ugo]+</em>)<b>\>/ </b> + // : user/group/other etc with specified location mode + // - <b> \<case\>/ </b> + // : The \c $FOAM_CASE directory + // - <b> \<constant\>/ </b> + // : The \c $FOAM_CASE/constant directory + // - <b> \<system\>/ </b> + // : The \c $FOAM_CASE/system directory // -# tilde expansion // - leading "~/" : home directory // - leading "~user" : home directory for specified user // // Supports default and alternative values as per the POSIX shell. // \code - // a) "${parameter:-defValue}" - // b) "${parameter:+altValue}" + // 1. "${parameter:-defValue}" + // 2. "${parameter:+altValue}" // \endcode - // a) If parameter is unset or null, the \c defValue is substituted. - // Otherwise, the value of parameter is substituted. - // - // b) If parameter is unset or null, nothing is substituted. - // Otherwise the \c altValue is substituted. + // -# If parameter is unset or null, the \c defValue is substituted. + // Otherwise, the value of parameter is substituted. + // -# If parameter is unset or null, nothing is substituted. + // Otherwise the \c altValue is substituted. + // . // + // General behavior: // - Any unknown entries are removed silently, if allowEmpty is true. // - Malformed entries (eg, brace mismatch, sigil followed by bad chars) - // are left as is. + // are left as is. + // + // An example of using the specified location mode + // \code + // fileName controlDict(stringOps::expand("<etc:o>/controlDict")); + // // OR + // fileName controlDict(findEtcFile("controlDict", false, 0007)); + // \endcode // // \note Deprecated(2018-11) Use "<etc>" instead of the rarely used // "~OpenFOAM" expansion @@ -263,28 +278,35 @@ namespace stringOps // -# current directory // - leading "./" : the current directory // -# leading tag expansion for commonly used directories - // - \<etc\>/ : user/group/other OpenFOAM directory - // - \<case\>/ : FOAM_CASE directory - // - \<constant\>/ : FOAM_CASE/constant directory - // - \<system\>/ : FOAM_CASE/system directory + // - <b> \<etc\>/ </b> + // : user/group/other OpenFOAM etc directory + // - <b> \<etc:</b><em>[ugo]+</em>)<b>\>/ </b> + // : user/group/other etc with specified location mode + // - <b> \<case\>/ </b> + // : The \c $FOAM_CASE directory + // - <b> \<constant\>/ </b> + // : The \c $FOAM_CASE/constant directory + // - <b> \<system\>/ </b> + // : The \c $FOAM_CASE/system directory // -# tilde expansion // - leading "~/" : home directory // - leading "~user" : home directory for specified user // // Supports default and alternative values as per the POSIX shell. // \code - // a) "${parameter:-defValue}" - // b) "${parameter:+altValue}" + // 1. "${parameter:-defValue}" + // 2. "${parameter:+altValue}" // \endcode - // a) If parameter is unset or null, the \c defValue is substituted. - // Otherwise, the value of parameter is substituted. - // - // b) If parameter is unset or null, nothing is substituted. - // Otherwise the \c altValue is substituted. + // -# If parameter is unset or null, the \c defValue is substituted. + // Otherwise, the value of parameter is substituted. + // -# If parameter is unset or null, nothing is substituted. + // Otherwise the \c altValue is substituted. + // . // + // General behavior: // - Any unknown entries are removed silently if allowEmpty is true. // - Malformed entries (eg, brace mismatch, sigil followed by bad chars) - // are left as is. + // are left as is. // // \note Deprecated(2018-11) Use "<etc>" instead of the rarely used // "~OpenFOAM" expansion