mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: improve output formatting for usage information
- generalize output text wrapping, use for usage notes - add -help-man option for generating manpage content for any OpenFOAM application or solver. bin/tools/foamCreateManpage as helper
This commit is contained in:
@ -140,7 +140,8 @@ HEADER
|
|||||||
# -opt1 descrip
|
# -opt1 descrip
|
||||||
# -opt2 <arg> descrip
|
# -opt2 <arg> descrip
|
||||||
# -help-full
|
# -help-full
|
||||||
# Terminate parsing on first appearance of -help-full
|
# Ignore -help-man (internal option).
|
||||||
|
# Terminate parsing on first appearance of -help-full.
|
||||||
# - options with '=' (eg, -mode=ugo) are not handled very well at all.
|
# - options with '=' (eg, -mode=ugo) are not handled very well at all.
|
||||||
# - alternatives (eg, -a, -all) are not handled nicely either,
|
# - alternatives (eg, -a, -all) are not handled nicely either,
|
||||||
# for these treat ',' like a space to catch the worst of them.
|
# for these treat ',' like a space to catch the worst of them.
|
||||||
@ -148,12 +149,15 @@ extractOptions()
|
|||||||
{
|
{
|
||||||
local appName="$1"
|
local appName="$1"
|
||||||
local helpText=$($appName -help-full 2>/dev/null | \
|
local helpText=$($appName -help-full 2>/dev/null | \
|
||||||
sed -ne 's/^ *//; /^$/d; /^[^-]/d; /^--/d;' \
|
sed -ne 's/^ *//; /^$/d; /^[^-]/d; /^--/d; /^-help-man/d;' \
|
||||||
-e 'y/,/ /; s/=.*$/=/;' \
|
-e 'y/,/ /; s/=.*$/=/;' \
|
||||||
-e '/^-[^ ]* </{ s/^\(-[^ ]* <\).*$/\1/; p; d }' \
|
-e '/^-[^ ]* </{ s/^\(-[^ ]* <\).*$/\1/; p; d }' \
|
||||||
-e 's/^\(-[^ ]*\).*$/\1/; p; /^-help-full/q;' \
|
-e 's/^\(-[^ ]*\).*$/\1/; p; /^-help-full/q;' \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# After this bit of sed, we have "-opt1" or "-opt2 <"
|
||||||
|
# for entries without or with arguments.
|
||||||
|
|
||||||
[ -n "$helpText" ] || {
|
[ -n "$helpText" ] || {
|
||||||
echo "Error calling $appName" 1>&2
|
echo "Error calling $appName" 1>&2
|
||||||
return 1
|
return 1
|
||||||
@ -163,8 +167,8 @@ extractOptions()
|
|||||||
local argOpts=($(awk '/</ {print $1}' <<< "$helpText"))
|
local argOpts=($(awk '/</ {print $1}' <<< "$helpText"))
|
||||||
|
|
||||||
# Array of options without args, but skip the following:
|
# Array of options without args, but skip the following:
|
||||||
# -help-compat -help-full
|
# -help-compat -help-full etc
|
||||||
local boolOpts=($(awk '!/</ && !/help-(compat|full)/ {print $1}' <<< "$helpText"))
|
local boolOpts=($(awk '!/</ && !/help-/ {print $1}' <<< "$helpText"))
|
||||||
|
|
||||||
appName="${appName##*/}"
|
appName="${appName##*/}"
|
||||||
echo "$appName" 1>&2
|
echo "$appName" 1>&2
|
||||||
|
|||||||
172
bin/tools/foamCreateManpage
Executable file
172
bin/tools/foamCreateManpage
Executable file
@ -0,0 +1,172 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# ========= |
|
||||||
|
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
# \\ / O peration |
|
||||||
|
# \\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
# \\/ M anipulation |
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# License
|
||||||
|
# This file is part of OpenFOAM, licensed under GNU General Public License
|
||||||
|
# <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# Script
|
||||||
|
# foamCreateManpage
|
||||||
|
#
|
||||||
|
# Description
|
||||||
|
# Query OpenFOAM applications with -help-man to generate manpage content.
|
||||||
|
#
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
defaultOutputDir="$WM_PROJECT_DIR/doc/man1"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
exec 1>&2
|
||||||
|
while [ "$#" -ge 1 ]; do echo "$1"; shift; done
|
||||||
|
cat<<USAGE
|
||||||
|
|
||||||
|
Usage: ${0##*/} [OPTION] [appName .. [appNameN]]
|
||||||
|
options:
|
||||||
|
-dir dir Directory to process
|
||||||
|
-gzip Compressed output
|
||||||
|
-o DIR Write to alternative output directory
|
||||||
|
-version VER Specify an alternative version
|
||||||
|
-h | -help Print the usage
|
||||||
|
|
||||||
|
Query OpenFOAM applications with -help-man for their manpage content
|
||||||
|
and redirect to corresponding directory location.
|
||||||
|
Default input: \$FOAM_APPBIN only.
|
||||||
|
Default output: $defaultOutputDir
|
||||||
|
|
||||||
|
Uses the search directory if applications are specified.
|
||||||
|
|
||||||
|
Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
USAGE
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Report error and exit
|
||||||
|
die()
|
||||||
|
{
|
||||||
|
exec 1>&2
|
||||||
|
echo
|
||||||
|
echo "Error encountered:"
|
||||||
|
while [ "$#" -ge 1 ]; do echo " $1"; shift; done
|
||||||
|
echo
|
||||||
|
echo "See '${0##*/} -help' for usage"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
searchDirs="$FOAM_APPBIN"
|
||||||
|
unset gzipFilter sedFilter outputDir
|
||||||
|
|
||||||
|
while [ "$#" -gt 0 ]
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-h | -help*)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
-d | -dir)
|
||||||
|
[ "$#" -ge 2 ] || die "'$1' option requires an argument"
|
||||||
|
searchDirs="$2"
|
||||||
|
[ -d "$searchDirs" ] || die "directory not found '$searchDirs'"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-gz | -gzip)
|
||||||
|
gzipFilter="gzip"
|
||||||
|
;;
|
||||||
|
-v | -version)
|
||||||
|
[ "$#" -ge 2 ] || die "'$1' option requires an argument"
|
||||||
|
version="$2"
|
||||||
|
sedFilter='s/OpenFOAM-[^\"]*/OpenFOAM-'"$version/"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-o | -output)
|
||||||
|
[ "$#" -ge 2 ] || die "'$1' option requires an argument"
|
||||||
|
outputDir="$2"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
die "unknown option: '$1'"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
: ${outputDir:=$defaultOutputDir}
|
||||||
|
|
||||||
|
# Verify that output is writeable
|
||||||
|
if [ -e "$outputDir" ]
|
||||||
|
then
|
||||||
|
[ -d "$outputDir" ] && [ -w "$outputDir" ] || \
|
||||||
|
die "Cannot write to $outputDir" "Not a directory, or no permission?"
|
||||||
|
else
|
||||||
|
mkdir -p "$outputDir" || \
|
||||||
|
die "Cannot create directory: $outputDir"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Pass through content, filter for version and/or gzip
|
||||||
|
#
|
||||||
|
|
||||||
|
tmpFile="$outputDir/${0##*/}"
|
||||||
|
trap "rm -fv $tmpFile >/dev/null; exit 0" EXIT TERM INT
|
||||||
|
|
||||||
|
process()
|
||||||
|
{
|
||||||
|
local appName="$1"
|
||||||
|
local outFile="$outputDir/${appName##*/}.1"
|
||||||
|
|
||||||
|
rm -f "$outFile"*;
|
||||||
|
|
||||||
|
"$appName" -help-man 2>/dev/null >| $tmpFile;
|
||||||
|
|
||||||
|
if grep -F -q "SYNOPSIS" "$tmpFile" 2>/dev/null
|
||||||
|
then
|
||||||
|
cat "$tmpFile" | \
|
||||||
|
sed -e "${sedFilter:-p}" | "${gzipFilter:-cat}" \
|
||||||
|
>| "$outFile${gzipFilter:+.gz}"
|
||||||
|
|
||||||
|
echo "$outFile${gzipFilter:+.gz}" 1>&2
|
||||||
|
else
|
||||||
|
echo "Problem with $appName" 1>&2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Default to standard search directories
|
||||||
|
[ "$#" -gt 0 ] || set -- ${searchDirs}
|
||||||
|
|
||||||
|
echo "Generating manpages from OpenFOAM applications" 1>&2
|
||||||
|
echo 1>&2
|
||||||
|
|
||||||
|
for item
|
||||||
|
do
|
||||||
|
if [ -d "$item" ]
|
||||||
|
then
|
||||||
|
# Process directory for applications - sort with ignore-case
|
||||||
|
echo "[directory] $item" 1>&2
|
||||||
|
choices="$(find $item -maxdepth 1 -executable -type f | sort -f 2>/dev/null)"
|
||||||
|
for appName in $choices
|
||||||
|
do
|
||||||
|
process $appName
|
||||||
|
done
|
||||||
|
elif command -v "$item" > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
process $item
|
||||||
|
else
|
||||||
|
echo "No such file or directory: $item" 1>&2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo 1>&2
|
||||||
|
echo "Done" 1>&2
|
||||||
|
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
@ -109,7 +109,7 @@ _of_complete_()
|
|||||||
local choices
|
local choices
|
||||||
|
|
||||||
case ${prev} in
|
case ${prev} in
|
||||||
-help | -help-compat | -help-full | -doc | -doc-source)
|
-help | -help-compat | -help-full | -help-man | -doc | -doc-source)
|
||||||
# These options are usage - we can stop now.
|
# These options are usage - we can stop now.
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
return 0
|
return 0
|
||||||
@ -138,6 +138,7 @@ _of_complete_()
|
|||||||
# -opt1 descrip
|
# -opt1 descrip
|
||||||
# -opt2 <arg> descrip
|
# -opt2 <arg> descrip
|
||||||
# -help-full
|
# -help-full
|
||||||
|
# Ignore -help-man (internal option).
|
||||||
# Terminate parsing on first appearance of -help-full
|
# Terminate parsing on first appearance of -help-full
|
||||||
# - options with '=' (eg, -mode=ugo) are not handled very well at all.
|
# - options with '=' (eg, -mode=ugo) are not handled very well at all.
|
||||||
# - alternatives (eg, -a, -all) are not handled nicely either,
|
# - alternatives (eg, -a, -all) are not handled nicely either,
|
||||||
@ -145,12 +146,15 @@ _of_complete_()
|
|||||||
if [ -z "$choices" ]
|
if [ -z "$choices" ]
|
||||||
then
|
then
|
||||||
local helpText=$($appName -help-full 2>/dev/null | \
|
local helpText=$($appName -help-full 2>/dev/null | \
|
||||||
sed -ne 's/^ *//; /^$/d; /^[^-]/d; /^--/d;' \
|
sed -ne 's/^ *//; /^$/d; /^[^-]/d; /^--/d; /^-help-man/d;' \
|
||||||
-e 'y/,/ /; s/=.*$/=/;' \
|
-e 'y/,/ /; s/=.*$/=/;' \
|
||||||
-e '/^-[^ ]* </{ s/^\(-[^ ]* <\).*$/\1/; p; d }' \
|
-e '/^-[^ ]* </{ s/^\(-[^ ]* <\).*$/\1/; p; d }' \
|
||||||
-e 's/^\(-[^ ]*\).*$/\1/; p; /^-help-full/q;' \
|
-e 's/^\(-[^ ]*\).*$/\1/; p; /^-help-full/q;' \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# After this bit of sed, we have "-opt1" or "-opt2 <"
|
||||||
|
# for entries without or with arguments.
|
||||||
|
|
||||||
if [ -z "$helpText" ]
|
if [ -z "$helpText" ]
|
||||||
then
|
then
|
||||||
echo "Error calling $appName" 1>&2
|
echo "Error calling $appName" 1>&2
|
||||||
|
|||||||
@ -2,6 +2,7 @@ global/global.Cver
|
|||||||
/* global/constants/constants.C in global.Cver */
|
/* global/constants/constants.C in global.Cver */
|
||||||
/* global/constants/dimensionedConstants.C in global.Cver */
|
/* global/constants/dimensionedConstants.C in global.Cver */
|
||||||
global/argList/argList.C
|
global/argList/argList.C
|
||||||
|
global/argList/argListHelp.C
|
||||||
global/clock/clock.C
|
global/clock/clock.C
|
||||||
global/profiling/profiling.C
|
global/profiling/profiling.C
|
||||||
global/profiling/profilingInformation.C
|
global/profiling/profilingInformation.C
|
||||||
|
|||||||
@ -436,9 +436,7 @@ void Foam::argList::printOptionUsage
|
|||||||
const string& str
|
const string& str
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const auto strLen = str.length();
|
if (str.empty())
|
||||||
|
|
||||||
if (!strLen)
|
|
||||||
{
|
{
|
||||||
Info<< nl;
|
Info<< nl;
|
||||||
return;
|
return;
|
||||||
@ -456,84 +454,7 @@ void Foam::argList::printOptionUsage
|
|||||||
++start;
|
++start;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string::size_type textWidth = (usageMax - usageMin);
|
stringOps::writeWrapped(Info, str, (usageMax-usageMin), usageMin);
|
||||||
|
|
||||||
// Output with text wrapping
|
|
||||||
for (std::string::size_type pos = 0; pos < strLen; /*ni*/)
|
|
||||||
{
|
|
||||||
// Potential end point and next point
|
|
||||||
std::string::size_type end = pos + textWidth - 1;
|
|
||||||
std::string::size_type eol = str.find('\n', pos);
|
|
||||||
std::string::size_type next = string::npos;
|
|
||||||
|
|
||||||
if (end >= strLen)
|
|
||||||
{
|
|
||||||
// No more wrapping needed
|
|
||||||
end = strLen;
|
|
||||||
|
|
||||||
if (std::string::npos != eol && eol <= end)
|
|
||||||
{
|
|
||||||
end = eol;
|
|
||||||
next = str.find_first_not_of(" \t\n", end); // Next non-space
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (std::string::npos != eol && eol <= end)
|
|
||||||
{
|
|
||||||
// Embedded '\n' char
|
|
||||||
end = eol;
|
|
||||||
next = str.find_first_not_of(" \t\n", end); // Next non-space
|
|
||||||
}
|
|
||||||
else if (isspace(str[end]))
|
|
||||||
{
|
|
||||||
// Ended on a space - can use this directly
|
|
||||||
next = str.find_first_not_of(" \t\n", end); // Next non-space
|
|
||||||
}
|
|
||||||
else if (isspace(str[end+1]))
|
|
||||||
{
|
|
||||||
// The next one is a space - so we are okay
|
|
||||||
++end; // Otherwise the length is wrong
|
|
||||||
next = str.find_first_not_of(" \t\n", end); // Next non-space
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Line break will be mid-word
|
|
||||||
auto prev = str.find_last_of(" \t\n", end); // Prev word break
|
|
||||||
|
|
||||||
if (std::string::npos != prev && prev > pos)
|
|
||||||
{
|
|
||||||
end = prev;
|
|
||||||
next = prev + 1; // Continue from here
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The next position to continue from
|
|
||||||
if (std::string::npos == next)
|
|
||||||
{
|
|
||||||
next = end + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has a length
|
|
||||||
if (end > pos)
|
|
||||||
{
|
|
||||||
// Indent following lines. The first one was already done.
|
|
||||||
if (pos)
|
|
||||||
{
|
|
||||||
for (std::string::size_type i = 0; i < usageMin; ++i)
|
|
||||||
{
|
|
||||||
Info<<' ';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (pos < end)
|
|
||||||
{
|
|
||||||
Info<< str[pos];
|
|
||||||
++pos;
|
|
||||||
}
|
|
||||||
Info<< nl;
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -960,6 +881,11 @@ void Foam::argList::parse
|
|||||||
printUsage(false);
|
printUsage(false);
|
||||||
quickExit = true;
|
quickExit = true;
|
||||||
}
|
}
|
||||||
|
else if (options_.found("help-man"))
|
||||||
|
{
|
||||||
|
printMan();
|
||||||
|
quickExit = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Allow independent display of compatibility information
|
// Allow independent display of compatibility information
|
||||||
if (options_.found("help-compat"))
|
if (options_.found("help-compat"))
|
||||||
@ -1584,13 +1510,21 @@ bool Foam::argList::unsetOption(const word& optName)
|
|||||||
|
|
||||||
void Foam::argList::printNotes() const
|
void Foam::argList::printNotes() const
|
||||||
{
|
{
|
||||||
// Output notes directly - no automatic text wrapping
|
// Output notes with automatic text wrapping
|
||||||
if (!notes.empty())
|
if (!notes.empty())
|
||||||
{
|
{
|
||||||
Info<< nl;
|
Info<< nl;
|
||||||
forAllConstIters(notes, iter)
|
|
||||||
|
for (const std::string& note : notes)
|
||||||
{
|
{
|
||||||
Info<< iter().c_str() << nl;
|
if (note.empty())
|
||||||
|
{
|
||||||
|
Info<< nl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stringOps::writeWrapped(Info, note, usageMax);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1610,10 +1544,10 @@ void Foam::argList::printUsage(bool full) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
label i = 0;
|
label i = 0;
|
||||||
forAllConstIters(validArgs, iter)
|
for (const std::string& argName : validArgs)
|
||||||
{
|
{
|
||||||
if (i++) Info<< ' ';
|
if (i++) Info<< ' ';
|
||||||
Info<< '<' << iter().c_str() << '>';
|
Info<< '<' << argName.c_str() << '>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!argsMandatory_)
|
if (!argsMandatory_)
|
||||||
@ -1677,6 +1611,12 @@ void Foam::argList::printUsage(bool full) const
|
|||||||
printOptionUsage(14, "Display compatibility options and exit");
|
printOptionUsage(14, "Display compatibility options and exit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (full)
|
||||||
|
{
|
||||||
|
Info<< " -help-man";
|
||||||
|
printOptionUsage(11, "Display full help (manpage format) and exit");
|
||||||
|
}
|
||||||
|
|
||||||
Info<< " -help-full";
|
Info<< " -help-full";
|
||||||
printOptionUsage(12, "Display full help and exit");
|
printOptionUsage(12, "Display full help and exit");
|
||||||
|
|
||||||
|
|||||||
@ -507,6 +507,9 @@ public:
|
|||||||
//- Print usage
|
//- Print usage
|
||||||
void printUsage(bool full=true) const;
|
void printUsage(bool full=true) const;
|
||||||
|
|
||||||
|
//- Print usage as nroff-man format (Experimental)
|
||||||
|
void printMan() const;
|
||||||
|
|
||||||
//- Display documentation in browser
|
//- Display documentation in browser
|
||||||
// Optionally display the application source code
|
// Optionally display the application source code
|
||||||
void displayDoc(bool source=false) const;
|
void displayDoc(bool source=false) const;
|
||||||
|
|||||||
222
src/OpenFOAM/global/argList/argListHelp.C
Normal file
222
src/OpenFOAM/global/argList/argListHelp.C
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||||
|
\\/ 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "argList.H"
|
||||||
|
#include "stringOps.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
// manpage Footer
|
||||||
|
static inline void printManFooter()
|
||||||
|
{
|
||||||
|
Info<< ".SH \"SEE ALSO\"" << nl
|
||||||
|
<< "Online documentation "
|
||||||
|
<< "https://www.openfoam.com/documentation/" << nl
|
||||||
|
<< ".SH COPYRIGHT" << nl
|
||||||
|
<< "Copyright 2018 OpenCFD Ltd." << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void printManOption(const word& optName)
|
||||||
|
{
|
||||||
|
Info<< ".TP" << nl << ".B \\-" << optName;
|
||||||
|
|
||||||
|
// Option has arg?
|
||||||
|
const auto optIter = argList::validOptions.cfind(optName);
|
||||||
|
if (optIter().size())
|
||||||
|
{
|
||||||
|
Info<< " <" << optIter().c_str() << '>';
|
||||||
|
}
|
||||||
|
Info<< nl;
|
||||||
|
|
||||||
|
// Option has usage information?
|
||||||
|
|
||||||
|
const auto usageIter = argList::optionUsage.cfind(optName);
|
||||||
|
if (usageIter.found())
|
||||||
|
{
|
||||||
|
stringOps::writeWrapped(Info, *usageIter, argList::usageMax, 0, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< nl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void Foam::argList::printMan() const
|
||||||
|
{
|
||||||
|
// .TH "<APPLICATION>" 1 "OpenFOAM-<version>" "source" "category"
|
||||||
|
|
||||||
|
Info
|
||||||
|
<< ".TH" << token::SPACE
|
||||||
|
// All uppercase and quoted
|
||||||
|
<< stringOps::upper(executable_) << token::SPACE
|
||||||
|
<< "\"1\"" << token::SPACE
|
||||||
|
<< token::DQUOTE << "OpenFOAM-v" << OPENFOAM << token::DQUOTE
|
||||||
|
<< token::SPACE
|
||||||
|
<< token::DQUOTE << "www.openfoam.com" << token::DQUOTE
|
||||||
|
<< token::SPACE
|
||||||
|
<< token::DQUOTE << "OpenFOAM Commands Manual" << token::DQUOTE
|
||||||
|
<< nl;
|
||||||
|
|
||||||
|
|
||||||
|
// .SH NAME
|
||||||
|
// <application> \- part of OpenFOAM (The Open Source CFD Toolbox).
|
||||||
|
Info
|
||||||
|
<< ".SH \"NAME\"" << nl
|
||||||
|
<< executable_
|
||||||
|
<< " \\- part of OpenFOAM (The Open Source CFD Toolbox)."
|
||||||
|
<< nl;
|
||||||
|
|
||||||
|
|
||||||
|
// .SH SYNOPSIS
|
||||||
|
// .B command [OPTIONS] ...
|
||||||
|
|
||||||
|
Info
|
||||||
|
<< ".SH \"SYNOPSIS\"" << nl
|
||||||
|
<< ".B " << executable_ << " [OPTIONS]";
|
||||||
|
|
||||||
|
if (validArgs.size())
|
||||||
|
{
|
||||||
|
Info<< ' ';
|
||||||
|
|
||||||
|
if (!argsMandatory_)
|
||||||
|
{
|
||||||
|
Info<< '[';
|
||||||
|
}
|
||||||
|
|
||||||
|
label i = 0;
|
||||||
|
for (const std::string& argName : validArgs)
|
||||||
|
{
|
||||||
|
if (i++) Info<< ' ';
|
||||||
|
Info << '<' << argName.c_str() << '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!argsMandatory_)
|
||||||
|
{
|
||||||
|
Info<< ']';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Info<< nl;
|
||||||
|
|
||||||
|
|
||||||
|
// .SH DESCRIPTION
|
||||||
|
{
|
||||||
|
Info
|
||||||
|
<< ".SH \"DESCRIPTION\"" << nl;
|
||||||
|
|
||||||
|
Info<< ".nf" << nl;
|
||||||
|
|
||||||
|
if (notes.empty())
|
||||||
|
{
|
||||||
|
Info<<"No description available\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< nl;
|
||||||
|
for (const std::string& note : notes)
|
||||||
|
{
|
||||||
|
if (note.empty())
|
||||||
|
{
|
||||||
|
Info<< nl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stringOps::writeWrapped(Info, note, usageMax, 0, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Info<< ".fi" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// .SH "OPTIONS"
|
||||||
|
Info
|
||||||
|
<< ".SH \"OPTIONS\"" << nl;
|
||||||
|
|
||||||
|
for (const word& optName : validOptions.sortedToc())
|
||||||
|
{
|
||||||
|
// Normal options
|
||||||
|
if (!advancedOptions.found(optName))
|
||||||
|
{
|
||||||
|
printManOption(optName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard documentation/help options
|
||||||
|
|
||||||
|
Info<< ".TP" << nl << ".B \\-" << "doc" << nl
|
||||||
|
<<"Display documentation in browser" << nl;
|
||||||
|
|
||||||
|
Info<< ".TP" << nl << ".B \\-" << "doc-source" << nl
|
||||||
|
<< "Display source code in browser" << nl;
|
||||||
|
|
||||||
|
Info<< ".TP" << nl << ".B \\-" << "help" << nl
|
||||||
|
<< "Display short help and exit" << nl;
|
||||||
|
|
||||||
|
Info<< ".TP" << nl << ".B \\-" << "help-full" << nl
|
||||||
|
<< "Display full help and exit" << nl;
|
||||||
|
|
||||||
|
|
||||||
|
// .SH "ADVANCED OPTIONS"
|
||||||
|
Info
|
||||||
|
<< ".SH \"ADVANCED OPTIONS\"" << nl;
|
||||||
|
|
||||||
|
for (const word& optName : validOptions.sortedToc())
|
||||||
|
{
|
||||||
|
// Advanced options
|
||||||
|
if (advancedOptions.found(optName))
|
||||||
|
{
|
||||||
|
printManOption(optName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compatibility information
|
||||||
|
if
|
||||||
|
(
|
||||||
|
argList::validOptionsCompat.size()
|
||||||
|
+ argList::ignoreOptionsCompat.size()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< ".TP" << nl << ".B \\-" << "help-compat" << nl
|
||||||
|
<< "Display compatibility options and exit" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< ".TP" << nl << ".B \\-" << "help-man" << nl
|
||||||
|
<< "Display full help (manpage format) and exit" << nl;
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
printManFooter();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -25,9 +25,10 @@ License
|
|||||||
|
|
||||||
#include "stringOps.H"
|
#include "stringOps.H"
|
||||||
#include "typeInfo.H"
|
#include "typeInfo.H"
|
||||||
#include "OSspecific.H"
|
|
||||||
#include "etcFiles.H"
|
#include "etcFiles.H"
|
||||||
#include "StringStream.H"
|
#include "StringStream.H"
|
||||||
|
#include "OSstream.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
@ -80,7 +81,7 @@ static void expandLeadingTag(std::string& s, const char b, const char e)
|
|||||||
}
|
}
|
||||||
else if (tag == "case")
|
else if (tag == "case")
|
||||||
{
|
{
|
||||||
s = fileName(getEnv("FOAM_CASE"))/file;
|
s = fileName(Foam::getEnv("FOAM_CASE"))/file;
|
||||||
}
|
}
|
||||||
else if (tag == "constant" || tag == "system")
|
else if (tag == "constant" || tag == "system")
|
||||||
{
|
{
|
||||||
@ -1090,4 +1091,109 @@ void Foam::stringOps::inplaceUpper(std::string& s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::stringOps::writeWrapped
|
||||||
|
(
|
||||||
|
OSstream& os,
|
||||||
|
const std::string& str,
|
||||||
|
const std::string::size_type width,
|
||||||
|
const std::string::size_type indent,
|
||||||
|
const bool escape
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const auto len = str.length();
|
||||||
|
|
||||||
|
std::string::size_type pos = 0;
|
||||||
|
|
||||||
|
// Handle leading newlines
|
||||||
|
while (str[pos] == '\n' && pos < len)
|
||||||
|
{
|
||||||
|
os << '\n';
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pos < len)
|
||||||
|
{
|
||||||
|
// Potential end point and next point
|
||||||
|
std::string::size_type end = pos + width - 1;
|
||||||
|
std::string::size_type eol = str.find('\n', pos);
|
||||||
|
std::string::size_type next = string::npos;
|
||||||
|
|
||||||
|
if (end >= len)
|
||||||
|
{
|
||||||
|
// No more wrapping needed
|
||||||
|
end = len;
|
||||||
|
|
||||||
|
if (std::string::npos != eol && eol <= end)
|
||||||
|
{
|
||||||
|
// Manual '\n' break, next follows it (default behaviour)
|
||||||
|
end = eol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (std::string::npos != eol && eol <= end)
|
||||||
|
{
|
||||||
|
// Manual '\n' break, next follows it (default behaviour)
|
||||||
|
end = eol;
|
||||||
|
}
|
||||||
|
else if (isspace(str[end]))
|
||||||
|
{
|
||||||
|
// Ended on a space - can use this directly
|
||||||
|
next = str.find_first_not_of(" \t\n", end); // Next non-space
|
||||||
|
}
|
||||||
|
else if (isspace(str[end+1]))
|
||||||
|
{
|
||||||
|
// The next one is a space - so we are okay
|
||||||
|
++end; // Otherwise the length is wrong
|
||||||
|
next = str.find_first_not_of(" \t\n", end); // Next non-space
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Line break will be mid-word
|
||||||
|
auto prev = str.find_last_of(" \t\n", end); // Prev word break
|
||||||
|
|
||||||
|
if (std::string::npos != prev && prev > pos)
|
||||||
|
{
|
||||||
|
end = prev;
|
||||||
|
next = prev + 1; // Continue from here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The next position to continue from
|
||||||
|
if (std::string::npos == next)
|
||||||
|
{
|
||||||
|
next = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has a length
|
||||||
|
if (end > pos)
|
||||||
|
{
|
||||||
|
// Indent following lines.
|
||||||
|
// The first one was already done prior to calling this routine.
|
||||||
|
if (pos)
|
||||||
|
{
|
||||||
|
for (std::string::size_type i = 0; i < indent; ++i)
|
||||||
|
{
|
||||||
|
os <<' ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pos < end)
|
||||||
|
{
|
||||||
|
const char c = str[pos];
|
||||||
|
|
||||||
|
if (escape && c == '\\')
|
||||||
|
{
|
||||||
|
os << '\\';
|
||||||
|
}
|
||||||
|
os << c;
|
||||||
|
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
os << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
@ -49,6 +49,9 @@ SourceFiles
|
|||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class OSstream;
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*\
|
/*---------------------------------------------------------------------------*\
|
||||||
Namespace stringOps Declaration
|
Namespace stringOps Declaration
|
||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
@ -382,6 +385,22 @@ namespace stringOps
|
|||||||
const StringType& str
|
const StringType& str
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//- Output string with text wrapping.
|
||||||
|
// Always includes a trailing newline, unless the string itself is empty.
|
||||||
|
//
|
||||||
|
// \param os the output stream
|
||||||
|
// \param str the text to be output
|
||||||
|
// \param width the max-width before wrapping
|
||||||
|
// \param indent indentation for continued lines
|
||||||
|
// \param escape escape any backslashes on output
|
||||||
|
void writeWrapped
|
||||||
|
(
|
||||||
|
OSstream& os,
|
||||||
|
const std::string& str,
|
||||||
|
const std::string::size_type width,
|
||||||
|
const std::string::size_type indent = 0,
|
||||||
|
const bool escape = false
|
||||||
|
);
|
||||||
|
|
||||||
} // End namespace stringOps
|
} // End namespace stringOps
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user