* To help us fund GROMACS development, we humbly ask that you cite
* the research papers on the package. Check out http://www.gromacs.org.
*/
-/* This file is completely threadsafe - keep it that way! */
-#include "gromacs/commandline/pargs.h"
+#include "gmxpre.h"
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "gromacs/commandline/pargs.h"
-#include <cctype>
-#include <cstdio>
#include <cstdlib>
#include <cstring>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "thread_mpi/threads.h"
-
-#include "gromacs/legacyheaders/gmx_fatal.h"
-#include "gromacs/legacyheaders/macros.h"
-#include "gromacs/legacyheaders/network.h"
+#include <algorithm>
+#include <list>
#include "gromacs/commandline/cmdlinehelpcontext.h"
#include "gromacs/commandline/cmdlinehelpwriter.h"
-#include "gromacs/commandline/shellcompletions.h"
+#include "gromacs/commandline/cmdlineparser.h"
#include "gromacs/fileio/timecontrol.h"
#include "gromacs/options/basicoptions.h"
#include "gromacs/options/filenameoption.h"
+#include "gromacs/options/filenameoptionmanager.h"
#include "gromacs/options/options.h"
+#include "gromacs/options/timeunitmanager.h"
#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/common.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/smalloc.h"
/* The source code in this file should be thread-safe.
Please keep it that way. */
-static void usage(const char *type, const char *arg)
-{
- GMX_ASSERT(arg != NULL, "NULL command-line argument should not occur");
- gmx_fatal(FARGS, "Expected %s argument for option %s\n", type, arg);
-}
-
-/* Scan an int for argument argv[*i] from argument at argv[*i + 1].
- * eg: -p 32. argv[*i] is only used for error reporting.
- * If there is no value, or the conversion is not successful, the
- * routine exits with an error, otherwise it returns the value found.
- * *i is incremented once.
- */
-static int iscan(int argc, char *argv[], int *i)
-{
- const char *const arg = argv[*i];
- if (argc <= (*i)+1)
- {
- usage("an integer", arg);
- }
- const char *const value = argv[++(*i)];
- char *endptr;
- int var = std::strtol(value, &endptr, 10);
- if (*value == '\0' || *endptr != '\0')
- {
- usage("an integer", arg);
- }
- return var;
-}
-
-/* Same as above, but for large integer values */
-static gmx_int64_t istepscan(int argc, char *argv[], int *i)
-{
- const char *const arg = argv[*i];
- if (argc <= (*i)+1)
- {
- usage("an integer", arg);
- }
- const char *const value = argv[++(*i)];
- char *endptr;
- gmx_int64_t var = str_to_int64_t(value, &endptr);
- if (*value == '\0' || *endptr != '\0')
- {
- usage("an integer", arg);
- }
- return var;
-}
-
-/* Routine similar to the above, but working on doubles. */
-static double dscan(int argc, char *argv[], int *i)
-{
- const char *const arg = argv[*i];
- if (argc <= (*i)+1)
- {
- usage("a real", arg);
- }
- const char *const value = argv[++(*i)];
- char *endptr;
- double var = std::strtod(value, &endptr);
- if (*value == '\0' || *endptr != '\0')
- {
- usage("a real", arg);
- }
- return var;
-}
-
-/* Routine similar to the above, but working on strings. The pointer
- * returned is a pointer to the argv field.
- */
-static char *sscan(int argc, char *argv[], int *i)
-{
- if (argc > (*i)+1)
- {
- if ( (argv[(*i)+1][0] == '-') && (argc > (*i)+2) &&
- (argv[(*i)+2][0] != '-') )
- {
- fprintf(stderr, "Possible missing string argument for option %s\n\n",
- argv[*i]);
- }
- }
- else
- {
- usage("a string", argv[*i]);
- }
-
- return argv[++(*i)];
-}
-
-static gmx_bool is_hidden(t_pargs *pa)
-{
- return (strstr(pa->desc, "HIDDEN") != NULL);
-}
-
int nenum(const char *const enumc[])
{
int i;
return i;
}
-/* Read a number of arguments from the command line.
- * For etINT, etREAL and etCHAR an extra argument is read (when present)
- * for etBOOL the gmx_boolean option is changed to the negate value
- */
-static void get_pargs(int *argc, char *argv[], int nparg, t_pargs pa[])
-{
- int i, j, k, match;
- gmx_bool *bKeep;
- char buf[32];
- char *ptr;
-
- snew(bKeep, *argc+1);
- bKeep[0] = TRUE;
- bKeep[*argc] = TRUE;
-
- for (i = 1; (i < *argc); i++)
- {
- bKeep[i] = TRUE;
- for (j = 0; (j < nparg); j++)
- {
- if (pa[j].type == etBOOL)
- {
- sprintf(buf, "-no%s", pa[j].option+1);
- if (strcmp(pa[j].option, argv[i]) == 0)
- {
- *pa[j].u.b = TRUE;
- pa[j].bSet = TRUE;
- bKeep[i] = FALSE;
- }
- else if (strcmp(buf, argv[i]) == 0)
- {
- *pa[j].u.b = FALSE;
- pa[j].bSet = TRUE;
- bKeep[i] = FALSE;
- }
- }
- else if (strcmp(pa[j].option, argv[i]) == 0)
- {
- if (pa[j].bSet)
- {
- fprintf(stderr, "Setting option %s more than once!\n",
- pa[j].option);
- }
- pa[j].bSet = TRUE;
- bKeep[i] = FALSE;
- switch (pa[j].type)
- {
- case etINT:
- *pa[j].u.i = iscan(*argc, argv, &i);
- break;
- case etINT64:
- *pa[j].u.is = istepscan(*argc, argv, &i);
- break;
- case etTIME:
- case etREAL:
- *pa[j].u.r = dscan(*argc, argv, &i);
- break;
- case etSTR:
- *(pa[j].u.c) = sscan(*argc, argv, &i);
- break;
- case etENUM:
- match = -1;
- ptr = sscan(*argc, argv, &i);
- for (k = 1; (pa[j].u.c[k] != NULL); k++)
- {
- /* only check ptr against beginning of
- pa[j].u.c[k] */
- if (gmx_strncasecmp(ptr, pa[j].u.c[k], strlen(ptr)) == 0)
- {
- if ( ( match == -1 ) ||
- ( strlen(pa[j].u.c[k]) <
- strlen(pa[j].u.c[match]) ) )
- {
- match = k;
- }
- }
- }
- if (match != -1)
- {
- pa[j].u.c[0] = pa[j].u.c[match];
- }
- else
- {
- gmx_fatal(FARGS, "Invalid argument %s for option %s",
- ptr, pa[j].option);
- }
- break;
- case etRVEC:
- (*pa[j].u.rv)[0] = dscan(*argc, argv, &i);
- if ( (i+1 == *argc) ||
- ( (argv[i+1][0] == '-') &&
- !isdigit(argv[i+1][1]) ) )
- {
- (*pa[j].u.rv)[1] =
- (*pa[j].u.rv)[2] =
- (*pa[j].u.rv)[0];
- }
- else
- {
- bKeep[i] = FALSE;
- (*pa[j].u.rv)[1] = dscan(*argc, argv, &i);
- if ( (i+1 == *argc) ||
- ( (argv[i+1][0] == '-') &&
- !isdigit(argv[i+1][1]) ) )
- {
- gmx_fatal(FARGS,
- "%s: vector must have 1 or 3 real parameters",
- pa[j].option);
- }
- bKeep[i] = FALSE;
- (*pa[j].u.rv)[2] = dscan(*argc, argv, &i);
- }
- break;
- default:
- gmx_fatal(FARGS, "Invalid type %d in pargs", pa[j].type);
- }
- /* i may be incremented, so set it to not keep */
- bKeep[i] = FALSE;
- }
- }
- }
-
- /* Remove used entries */
- for (i = j = 0; (i <= *argc); i++)
- {
- if (bKeep[i])
- {
- argv[j++] = argv[i];
- }
- }
- (*argc) = j-1;
- sfree(bKeep);
-}
-
int opt2parg_int(const char *option, int nparg, t_pargs pa[])
{
int i;
* parse_common_args()
*/
-static void set_default_time_unit(const char *time_list[], gmx_bool bCanTime)
+namespace gmx
{
- int i = 0;
- const char *select = NULL;
-
- if (bCanTime)
- {
- select = getenv("GMXTIMEUNIT");
- if (select != NULL)
- {
- i = 1;
- while (time_list[i] && strcmp(time_list[i], select) != 0)
- {
- i++;
- }
- }
- }
- if (!bCanTime || select == NULL ||
- time_list[i] == NULL || strcmp(time_list[i], select) != 0)
- {
- /* Set it to the default: ps */
- i = 1;
- while (time_list[i] && strcmp(time_list[i], "ps") != 0)
- {
- i++;
- }
-
- }
- time_list[0] = time_list[i];
-}
-static void set_default_xvg_format(const char *xvg_list[])
+namespace
{
- int i;
- const char *select;
- select = getenv("GMX_VIEW_XVG");
- if (select == NULL)
- {
- /* The default is the first option */
- xvg_list[0] = xvg_list[1];
- }
- else
+/*! \brief
+ * Returns the index of the default xvg format.
+ *
+ * \ingroup module_commandline
+ */
+int getDefaultXvgFormat(gmx::ConstArrayRef<const char *> xvgFormats)
+{
+ const char *const select = getenv("GMX_VIEW_XVG");
+ if (select != NULL)
{
- i = 1;
- while (xvg_list[i] && strcmp(xvg_list[i], select) != 0)
- {
- i++;
- }
- if (xvg_list[i] != NULL)
+ ConstArrayRef<const char *>::const_iterator i =
+ std::find(xvgFormats.begin(), xvgFormats.end(), std::string(select));
+ if (i != xvgFormats.end())
{
- xvg_list[0] = xvg_list[i];
+ return i - xvgFormats.begin();
}
else
{
- xvg_list[0] = xvg_list[exvgNONE];
+ return exvgNONE - 1;
}
}
+ /* The default is the first option */
+ return 0;
}
-static int add_parg(int npargs, t_pargs *pa, t_pargs *pa_add)
-{
- memcpy(&(pa[npargs]), pa_add, sizeof(*pa_add));
-
- return npargs+1;
-}
-
-namespace gmx
-{
-
-namespace
-{
-
/*! \brief
- * Converts a t_filenm option into an Options option.
+ * Conversion helper between t_pargs/t_filenm and Options.
*
- * \param options Options object to add the new option to.
- * \param[in] fnm t_filenm option to convert.
+ * This class holds the necessary mapping between the old C structures and
+ * the new C++ options to allow copying values back after parsing for cases
+ * where the C++ options do not directly provide the type of value required for
+ * the C structures.
*
* \ingroup module_commandline
*/
-void filenmToOptions(Options *options, const t_filenm *fnm)
+class OptionsAdapter
+{
+ public:
+ /*! \brief
+ * Initializes the adapter to convert from a specified command line.
+ *
+ * The command line is required, because t_pargs wants to return
+ * strings by reference to the original command line.
+ * OptionsAdapter creates a copy of the `argv` array (but not the
+ * strings) to make this possible, even if the parser removes
+ * options it has recognized.
+ */
+ OptionsAdapter(int argc, const char *const argv[])
+ : argv_(argv, argv + argc)
+ {
+ }
+
+ /*! \brief
+ * Converts a t_filenm option into an Options option.
+ *
+ * \param options Options object to add the new option to.
+ * \param fnm t_filenm option to convert.
+ */
+ void filenmToOptions(Options *options, t_filenm *fnm);
+ /*! \brief
+ * Converts a t_pargs option into an Options option.
+ *
+ * \param options Options object to add the new option to.
+ * \param pa t_pargs option to convert.
+ */
+ void pargsToOptions(Options *options, t_pargs *pa);
+
+ /*! \brief
+ * Copies values back from options to t_pargs/t_filenm.
+ */
+ void copyValues(bool bReadNode);
+
+ private:
+ struct FileNameData
+ {
+ //! Creates a conversion helper for a given `t_filenm` struct.
+ explicit FileNameData(t_filenm *fnm) : fnm(fnm), optionInfo(NULL)
+ {
+ }
+
+ //! t_filenm structure to receive the final values.
+ t_filenm *fnm;
+ //! Option info object for the created FileNameOption.
+ FileNameOptionInfo *optionInfo;
+ //! Value storage for the created FileNameOption.
+ std::vector<std::string> values;
+ };
+ struct ProgramArgData
+ {
+ //! Creates a conversion helper for a given `t_pargs` struct.
+ explicit ProgramArgData(t_pargs *pa)
+ : pa(pa), optionInfo(NULL), enumIndex(0), boolValue(false)
+ {
+ }
+
+ //! t_pargs structure to receive the final values.
+ t_pargs *pa;
+ //! Option info object for the created option.
+ OptionInfo *optionInfo;
+ //! Value storage for a non-enum StringOption (unused for other types).
+ std::string stringValue;
+ //! Value storage for an enum option (unused for other types).
+ int enumIndex;
+ //! Value storage for a BooleanOption (unused for other types).
+ bool boolValue;
+ };
+
+ std::vector<const char *> argv_;
+ // These are lists instead of vectors to avoid relocating existing
+ // objects in case the container is reallocated (the Options object
+ // contains pointes to members of the objects, which would get
+ // invalidated).
+ std::list<FileNameData> fileNameOptions_;
+ std::list<ProgramArgData> programArgs_;
+
+ GMX_DISALLOW_COPY_AND_ASSIGN(OptionsAdapter);
+};
+
+void OptionsAdapter::filenmToOptions(Options *options, t_filenm *fnm)
{
+ if (fnm->opt == NULL)
+ {
+ // Existing code may use opt2fn() instead of ftp2fn() for
+ // options that use the default option name, so we need to
+ // keep the old behavior instead of fixing opt2fn().
+ // TODO: Check that this is not the case, remove this, and make
+ // opt2*() work even if fnm->opt is NULL for some options.
+ fnm->opt = ftp2defopt(fnm->ftp);
+ }
const bool bRead = ((fnm->flag & ffREAD) != 0);
const bool bWrite = ((fnm->flag & ffWRITE) != 0);
const bool bOptional = ((fnm->flag & ffOPT) != 0);
{
defName = ftp2defnm(fnm->ftp);
}
- // Since we are not (yet) using this for actual parsing, we don't need to
- // set any storage.
- options->addOption(
- FileNameOption(name).defaultBasename(defName).legacyType(fnm->ftp)
- .readWriteFlags(bRead, bWrite).required(!bOptional)
- .libraryFile(bLibrary).multiValue(bMultiple)
- .description(ftp2desc(fnm->ftp)));
+ fileNameOptions_.push_back(FileNameData(fnm));
+ FileNameData &data = fileNameOptions_.back();
+ data.optionInfo = options->addOption(
+ FileNameOption(name).storeVector(&data.values)
+ .defaultBasename(defName).legacyType(fnm->ftp)
+ .legacyOptionalBehavior()
+ .readWriteFlags(bRead, bWrite).required(!bOptional)
+ .libraryFile(bLibrary).multiValue(bMultiple)
+ .description(ftp2desc(fnm->ftp)));
}
-/*! \brief
- * Converts a t_pargs option into an Options option.
- *
- * \param options Options object to add the new option to.
- * \param[in] pa t_pargs option to convert.
- *
- * \ingroup module_commandline
- */
-void pargsToOptions(Options *options, t_pargs *pa)
+void OptionsAdapter::pargsToOptions(Options *options, t_pargs *pa)
{
- const bool bHidden = is_hidden(pa);
+ const bool bHidden = startsWith(pa->desc, "HIDDEN");
const char *const name = &pa->option[1];
const char *const desc = (bHidden ? &pa->desc[6] : pa->desc);
- // Since we are not (yet) using this for actual parsing, we can take some
- // shortcuts and not set any storage where there is no direct
- // correspondence in the types.
+ programArgs_.push_back(ProgramArgData(pa));
+ ProgramArgData &data = programArgs_.back();
switch (pa->type)
{
case etINT:
- options->addOption(
- IntegerOption(name).store(pa->u.i)
- .description(desc).hidden(bHidden));
+ data.optionInfo = options->addOption(
+ IntegerOption(name).store(pa->u.i)
+ .description(desc).hidden(bHidden));
return;
case etINT64:
- options->addOption(
- Int64Option(name).store(pa->u.is)
- .description(desc).hidden(bHidden));
+ data.optionInfo = options->addOption(
+ Int64Option(name).store(pa->u.is)
+ .description(desc).hidden(bHidden));
return;
case etREAL:
- options->addOption(
- RealOption(name).store(pa->u.r)
- .description(desc).hidden(bHidden));
+ data.optionInfo = options->addOption(
+ RealOption(name).store(pa->u.r)
+ .description(desc).hidden(bHidden));
return;
case etTIME:
- options->addOption(
- RealOption(name).store(pa->u.r).timeValue()
- .description(desc).hidden(bHidden));
+ data.optionInfo = options->addOption(
+ RealOption(name).store(pa->u.r).timeValue()
+ .description(desc).hidden(bHidden));
return;
case etSTR:
{
const char *const defValue = (*pa->u.c != NULL ? *pa->u.c : "");
- options->addOption(
- StringOption(name).defaultValue(defValue)
- .description(desc).hidden(bHidden));
+ data.optionInfo = options->addOption(
+ StringOption(name).store(&data.stringValue)
+ .defaultValue(defValue)
+ .description(desc).hidden(bHidden));
return;
}
case etBOOL:
- options->addOption(
- BooleanOption(name).defaultValue(*pa->u.b)
- .description(desc).hidden(bHidden));
+ data.optionInfo = options->addOption(
+ BooleanOption(name).store(&data.boolValue)
+ .defaultValue(*pa->u.b)
+ .description(desc).hidden(bHidden));
return;
case etRVEC:
- options->addOption(
- RealOption(name).store(*pa->u.rv).vector()
- .description(desc).hidden(bHidden));
+ data.optionInfo = options->addOption(
+ RealOption(name).store(*pa->u.rv).vector()
+ .description(desc).hidden(bHidden));
return;
case etENUM:
- options->addOption(
- StringOption(name).defaultEnumIndex(nenum(pa->u.c) - 1)
- .enumValueFromNullTerminatedArray(pa->u.c + 1)
- .description(desc).hidden(bHidden));
+ {
+ const int defaultIndex = (pa->u.c[0] != NULL ? nenum(pa->u.c) - 1 : 0);
+ data.optionInfo = options->addOption(
+ StringOption(name).storeEnumIndex(&data.enumIndex)
+ .defaultEnumIndex(defaultIndex)
+ .enumValueFromNullTerminatedArray(pa->u.c + 1)
+ .description(desc).hidden(bHidden));
return;
+ }
}
GMX_THROW(NotImplementedError("Argument type not implemented"));
}
+void OptionsAdapter::copyValues(bool bReadNode)
+{
+ std::list<FileNameData>::const_iterator file;
+ for (file = fileNameOptions_.begin(); file != fileNameOptions_.end(); ++file)
+ {
+ if (!bReadNode && (file->fnm->flag & ffREAD))
+ {
+ continue;
+ }
+ if (file->optionInfo->isSet())
+ {
+ file->fnm->flag |= ffSET;
+ }
+ file->fnm->nfiles = file->values.size();
+ snew(file->fnm->fns, file->fnm->nfiles);
+ for (int i = 0; i < file->fnm->nfiles; ++i)
+ {
+ file->fnm->fns[i] = gmx_strdup(file->values[i].c_str());
+ }
+ }
+ std::list<ProgramArgData>::const_iterator arg;
+ for (arg = programArgs_.begin(); arg != programArgs_.end(); ++arg)
+ {
+ arg->pa->bSet = arg->optionInfo->isSet();
+ switch (arg->pa->type)
+ {
+ case etSTR:
+ {
+ if (arg->pa->bSet)
+ {
+ std::vector<const char *>::const_iterator pos =
+ std::find(argv_.begin(), argv_.end(), arg->stringValue);
+ GMX_RELEASE_ASSERT(pos != argv_.end(),
+ "String argument got a value not in argv");
+ *arg->pa->u.c = *pos;
+ }
+ break;
+ }
+ case etBOOL:
+ *arg->pa->u.b = arg->boolValue;
+ break;
+ case etENUM:
+ *arg->pa->u.c = arg->pa->u.c[arg->enumIndex + 1];
+ break;
+ default:
+ // For other types, there is nothing type-specific to do.
+ break;
+ }
+ }
+}
+
} // namespace
} // namespace gmx
output_env_t *oenv)
{
/* This array should match the order of the enum in oenv.h */
- const char *xvg_format[] = { NULL, "xmgrace", "xmgr", "none", NULL };
- /* This array should match the order of the enum in oenv.h */
- const char *time_units[] = {
- NULL, "fs", "ps", "ns", "us", "ms", "s",
- NULL
- };
- int nicelevel = 0, debug_level = 0;
- char *deffnm = NULL;
- real tbegin = 0, tend = 0, tdelta = 0;
- gmx_bool bView = FALSE;
-
- t_pargs *all_pa = NULL;
-
- t_pargs nice_pa = {
- "-nice", FALSE, etINT, {&nicelevel},
- "Set the nicelevel"
- };
- t_pargs deffnm_pa = {
- "-deffnm", FALSE, etSTR, {&deffnm},
- "Set the default filename for all file options"
- };
- t_pargs begin_pa = {
- "-b", FALSE, etTIME, {&tbegin},
- "First frame (%t) to read from trajectory"
- };
- t_pargs end_pa = {
- "-e", FALSE, etTIME, {&tend},
- "Last frame (%t) to read from trajectory"
- };
- t_pargs dt_pa = {
- "-dt", FALSE, etTIME, {&tdelta},
- "Only use frame when t MOD dt = first time (%t)"
- };
- t_pargs view_pa = {
- "-w", FALSE, etBOOL, {&bView},
- "View output [TT].xvg[tt], [TT].xpm[tt], [TT].eps[tt] and [TT].pdb[tt] files"
- };
- t_pargs xvg_pa = {
- "-xvg", FALSE, etENUM, {xvg_format},
- "xvg plot formatting"
- };
- t_pargs time_pa = {
- "-tu", FALSE, etENUM, {time_units},
- "Time unit"
- };
- /* Maximum number of extra arguments */
-#define EXTRA_PA 16
-
- t_pargs pca_pa[] = {
- { "-debug", FALSE, etINT, {&debug_level},
- "HIDDENWrite file with debug information, 1: short, 2: also x and f" },
- };
-#define NPCA_PA asize(pca_pa)
- gmx_bool bXvgr;
- int i, j, k, npall, max_pa;
+ const char *const xvg_formats[] = { "xmgrace", "xmgr", "none" };
// Handle the flags argument, which is a bit field
// The FF macro returns whether or not the bit is set
#define FF(arg) ((Flags & arg) == arg)
- /* Check for double arguments */
- for (i = 1; (i < *argc); i++)
- {
- if (argv[i] && (strlen(argv[i]) > 1) && (!std::isdigit(argv[i][1])))
- {
- for (j = i+1; (j < *argc); j++)
- {
- if ( (argv[i][0] == '-') && (argv[j][0] == '-') &&
- (strcmp(argv[i], argv[j]) == 0) )
- {
- if (FF(PCA_NOEXIT_ON_ARGS))
- {
- fprintf(stderr, "Double command line argument %s\n",
- argv[i]);
- }
- else
- {
- gmx_fatal(FARGS, "Double command line argument %s\n",
- argv[i]);
- }
- }
- }
- }
- }
- debug_gmx();
-
- /* Check ALL the flags ... */
- max_pa = NPCA_PA + EXTRA_PA + npargs+1;
- snew(all_pa, max_pa);
-
- for (i = npall = 0; (i < static_cast<int>(NPCA_PA)); i++)
- {
- npall = add_parg(npall, all_pa, &(pca_pa[i]));
- }
-
- if (FF(PCA_BE_NICE))
- {
- nicelevel = 19;
- }
- npall = add_parg(npall, all_pa, &nice_pa);
-
- if (FF(PCA_CAN_SET_DEFFNM))
- {
- npall = add_parg(npall, all_pa, &deffnm_pa);
- }
- if (FF(PCA_CAN_BEGIN))
- {
- npall = add_parg(npall, all_pa, &begin_pa);
- }
- if (FF(PCA_CAN_END))
- {
- npall = add_parg(npall, all_pa, &end_pa);
- }
- if (FF(PCA_CAN_DT))
- {
- npall = add_parg(npall, all_pa, &dt_pa);
- }
- if (FF(PCA_TIME_UNIT))
- {
- npall = add_parg(npall, all_pa, &time_pa);
- }
- if (FF(PCA_CAN_VIEW))
- {
- npall = add_parg(npall, all_pa, &view_pa);
- }
-
- bXvgr = FALSE;
- for (i = 0; (i < nfile); i++)
- {
- bXvgr = bXvgr || (fnm[i].ftp == efXVG);
- }
- if (bXvgr)
+ try
{
- npall = add_parg(npall, all_pa, &xvg_pa);
- }
+ double tbegin = 0.0, tend = 0.0, tdelta = 0.0;
+ bool bView = false;
+ int xvgFormat = 0;
+ gmx::TimeUnitManager timeUnitManager;
+ gmx::OptionsAdapter adapter(*argc, argv);
+ gmx::Options options(NULL, NULL);
+ gmx::FileNameOptionManager fileOptManager;
- /* Now append the program specific arguments */
- for (i = 0; (i < npargs); i++)
- {
- npall = add_parg(npall, all_pa, &(pa[i]));
- }
+ fileOptManager.disableInputOptionChecking(
+ FF(PCA_NOT_READ_NODE) || FF(PCA_DISABLE_INPUT_FILE_CHECKING));
+ options.addManager(&fileOptManager);
+ options.setDescription(gmx::constArrayRefFromArray<const char *>(desc, ndesc));
- /* set etENUM options to default */
- for (i = 0; (i < npall); i++)
- {
- if (all_pa[i].type == etENUM)
+ if (FF(PCA_CAN_SET_DEFFNM))
{
- all_pa[i].u.c[0] = all_pa[i].u.c[1];
+ fileOptManager.addDefaultFileNameOption(&options, "deffnm");
}
- }
- set_default_time_unit(time_units, FF(PCA_TIME_UNIT));
- set_default_xvg_format(xvg_format);
-
- /* Now parse all the command-line options */
- get_pargs(argc, argv, npall, all_pa);
-
- /* set program name, command line, and default values for output options */
- output_env_init(oenv, gmx::getProgramContext(), (time_unit_t)nenum(time_units), bView,
- (xvg_format_t)nenum(xvg_format), 0, debug_level);
-
- /* Parse the file args */
- parse_file_args(argc, argv, nfile, fnm, deffnm, !FF(PCA_NOT_READ_NODE));
-
- /* Open the debug file */
- if (debug_level > 0)
- {
- char buf[256];
-
- if (gmx_mpi_initialized())
+ if (FF(PCA_CAN_BEGIN))
{
- sprintf(buf, "%s%d.debug", output_env_get_short_program_name(*oenv),
- gmx_node_rank());
+ options.addOption(
+ gmx::DoubleOption("b").store(&tbegin).timeValue()
+ .description("First frame (%t) to read from trajectory"));
}
- else
+ if (FF(PCA_CAN_END))
+ {
+ options.addOption(
+ gmx::DoubleOption("e").store(&tend).timeValue()
+ .description("Last frame (%t) to read from trajectory"));
+ }
+ if (FF(PCA_CAN_DT))
+ {
+ options.addOption(
+ gmx::DoubleOption("dt").store(&tdelta).timeValue()
+ .description("Only use frame when t MOD dt = first time (%t)"));
+ }
+ if (FF(PCA_TIME_UNIT))
+ {
+ timeUnitManager.setTimeUnitFromEnvironment();
+ timeUnitManager.addTimeUnitOption(&options, "tu");
+ }
+ if (FF(PCA_CAN_VIEW))
{
- sprintf(buf, "%s.debug", output_env_get_short_program_name(*oenv));
+ options.addOption(
+ gmx::BooleanOption("w").store(&bView)
+ .description("View output [TT].xvg[tt], [TT].xpm[tt], "
+ "[TT].eps[tt] and [TT].pdb[tt] files"));
}
- init_debug(debug_level, buf);
- fprintf(stderr, "Opening debug file %s (src code file %s, line %d)\n",
- buf, __FILE__, __LINE__);
- }
+ bool bXvgr = false;
+ for (int i = 0; i < nfile; i++)
+ {
+ bXvgr = bXvgr || (fnm[i].ftp == efXVG);
+ }
+ xvgFormat = gmx::getDefaultXvgFormat(xvg_formats);
+ if (bXvgr)
+ {
+ options.addOption(
+ gmx::StringOption("xvg").enumValue(xvg_formats)
+ .storeEnumIndex(&xvgFormat)
+ .description("xvg plot formatting"));
+ }
- /* Now copy the results back... */
- for (i = 0, k = npall-npargs; (i < npargs); i++, k++)
- {
- memcpy(&(pa[i]), &(all_pa[k]), (size_t)sizeof(pa[i]));
- }
+ /* Now append the program specific arguments */
+ for (int i = 0; i < nfile; i++)
+ {
+ adapter.filenmToOptions(&options, &fnm[i]);
+ }
+ for (int i = 0; i < npargs; i++)
+ {
+ adapter.pargsToOptions(&options, &pa[i]);
+ }
- bool bExit = false;
- try
- {
const gmx::CommandLineHelpContext *context =
gmx::GlobalCommandLineHelpContext::get();
- bExit = (context != NULL);
- if (context != NULL && !(FF(PCA_QUIET)))
+ if (context != NULL)
{
- gmx::Options options(NULL, NULL);
- options.setDescription(gmx::ConstArrayRef<const char *>(desc, ndesc));
- for (i = 0; i < nfile; i++)
- {
- gmx::filenmToOptions(&options, &fnm[i]);
- }
- for (i = 0; i < npall; i++)
- {
- gmx::pargsToOptions(&options, &all_pa[i]);
- }
+ GMX_RELEASE_ASSERT(gmx_node_rank() == 0,
+ "Help output should be handled higher up and "
+ "only get called only on the master rank");
gmx::CommandLineHelpWriter(options)
.setShowDescriptions(true)
- .setTimeUnitString(output_env_get_time_unit(*oenv))
- .setKnownIssues(gmx::ConstArrayRef<const char *>(bugs, nbugs))
+ .setTimeUnitString(timeUnitManager.timeUnitAsString())
+ .setKnownIssues(gmx::constArrayRefFromArray(bugs, nbugs))
.writeHelp(*context);
+ return FALSE;
}
- }
- GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
- /* Set the nice level */
-#ifdef HAVE_UNISTD_H
-#ifndef GMX_NO_NICE
- /* The some system, e.g. the catamount kernel on cray xt3 do not have nice(2). */
- if (nicelevel != 0 && !bExit)
- {
- static gmx_bool nice_set = FALSE; /* only set it once */
- static tMPI_Thread_mutex_t init_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
- tMPI_Thread_mutex_lock(&init_mutex);
- if (!nice_set)
- {
- if (nice(nicelevel) == -1)
- {
- /* Do nothing, but use the return value to avoid warnings. */
- }
- nice_set = TRUE;
- }
- tMPI_Thread_mutex_unlock(&init_mutex);
- }
-#endif
-#endif
+ /* Now parse all the command-line options */
+ gmx::CommandLineParser(&options).skipUnknown(FF(PCA_NOEXIT_ON_ARGS))
+ .parse(argc, argv);
+ options.finish();
- /* convert time options, must be done after printing! */
+ /* set program name, command line, and default values for output options */
+ output_env_init(oenv, gmx::getProgramContext(),
+ (time_unit_t)(timeUnitManager.timeUnit() + 1), bView,
+ (xvg_format_t)(xvgFormat + 1), 0);
- for (i = 0; i < npall; i++)
- {
- if (all_pa[i].type == etTIME && all_pa[i].bSet)
+ timeUnitManager.scaleTimeOptions(&options);
+
+ /* Extract Time info from arguments */
+ // TODO: Use OptionInfo objects instead of string constants
+ if (FF(PCA_CAN_BEGIN) && options.isSet("b"))
{
- *all_pa[i].u.r *= output_env_get_time_invfactor(*oenv);
+ setTimeValue(TBEGIN, tbegin);
}
- }
-
- /* Extract Time info from arguments */
- if (FF(PCA_CAN_BEGIN) && opt2parg_bSet("-b", npall, all_pa))
- {
- setTimeValue(TBEGIN, opt2parg_real("-b", npall, all_pa));
- }
-
- if (FF(PCA_CAN_END) && opt2parg_bSet("-e", npall, all_pa))
- {
- setTimeValue(TEND, opt2parg_real("-e", npall, all_pa));
- }
-
- if (FF(PCA_CAN_DT) && opt2parg_bSet("-dt", npall, all_pa))
- {
- setTimeValue(TDELTA, opt2parg_real("-dt", npall, all_pa));
- }
-
- /* clear memory */
- sfree(all_pa);
-
- if (!FF(PCA_NOEXIT_ON_ARGS))
- {
- if (*argc > 1)
+ if (FF(PCA_CAN_END) && options.isSet("e"))
+ {
+ setTimeValue(TEND, tend);
+ }
+ if (FF(PCA_CAN_DT) && options.isSet("dt"))
{
- gmx_cmd(argv[1]);
+ setTimeValue(TDELTA, tdelta);
}
+
+ adapter.copyValues(!FF(PCA_NOT_READ_NODE));
+
+ return TRUE;
}
- return !bExit;
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
#undef FF
}