2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 /* This file is completely threadsafe - keep it that way! */
38 #include "gromacs/commandline/pargs.h"
55 #include <sys/schedctl.h>
56 #include <sys/sysmp.h>
59 #include "thread_mpi/threads.h"
61 #include "gromacs/legacyheaders/gmx_fatal.h"
62 #include "gromacs/legacyheaders/macros.h"
63 #include "gromacs/legacyheaders/network.h"
65 #include "gromacs/commandline/cmdlinehelpcontext.h"
66 #include "gromacs/commandline/cmdlinehelpwriter.h"
67 #include "gromacs/commandline/shellcompletions.h"
68 #include "gromacs/fileio/timecontrol.h"
69 #include "gromacs/options/basicoptions.h"
70 #include "gromacs/options/filenameoption.h"
71 #include "gromacs/options/options.h"
72 #include "gromacs/utility/arrayref.h"
73 #include "gromacs/utility/cstringutil.h"
74 #include "gromacs/utility/exceptions.h"
75 #include "gromacs/utility/gmxassert.h"
76 #include "gromacs/utility/programcontext.h"
77 #include "gromacs/utility/smalloc.h"
78 #include "gromacs/utility/stringutil.h"
80 /* The source code in this file should be thread-safe.
81 Please keep it that way. */
83 static void usage(const char *type, const char *arg)
85 GMX_ASSERT(arg != NULL, "NULL command-line argument should not occur");
86 gmx_fatal(FARGS, "Expected %s argument for option %s\n", type, arg);
89 /* Scan an int for argument argv[*i] from argument at argv[*i + 1].
90 * eg: -p 32. argv[*i] is only used for error reporting.
91 * If there is no value, or the conversion is not successful, the
92 * routine exits with an error, otherwise it returns the value found.
93 * *i is incremented once.
95 static int iscan(int argc, char *argv[], int *i)
97 const char *const arg = argv[*i];
100 usage("an integer", arg);
102 const char *const value = argv[++(*i)];
104 int var = std::strtol(value, &endptr, 10);
105 if (*value == '\0' || *endptr != '\0')
107 usage("an integer", arg);
112 /* Same as above, but for large integer values */
113 static gmx_int64_t istepscan(int argc, char *argv[], int *i)
115 const char *const arg = argv[*i];
118 usage("an integer", arg);
120 const char *const value = argv[++(*i)];
122 gmx_int64_t var = str_to_int64_t(value, &endptr);
123 if (*value == '\0' || *endptr != '\0')
125 usage("an integer", arg);
130 /* Routine similar to the above, but working on doubles. */
131 static double dscan(int argc, char *argv[], int *i)
133 const char *const arg = argv[*i];
136 usage("a real", arg);
138 const char *const value = argv[++(*i)];
140 double var = std::strtod(value, &endptr);
141 if (*value == '\0' || *endptr != '\0')
143 usage("a real", arg);
148 /* Routine similar to the above, but working on strings. The pointer
149 * returned is a pointer to the argv field.
151 static char *sscan(int argc, char *argv[], int *i)
155 if ( (argv[(*i)+1][0] == '-') && (argc > (*i)+2) &&
156 (argv[(*i)+2][0] != '-') )
158 fprintf(stderr, "Possible missing string argument for option %s\n\n",
164 usage("a string", argv[*i]);
170 static gmx_bool is_hidden(t_pargs *pa)
172 return (strstr(pa->desc, "HIDDEN") != NULL);
175 int nenum(const char *const enumc[])
180 /* we *can* compare pointers directly here! */
181 while (enumc[i] && enumc[0] != enumc[i])
189 /* Read a number of arguments from the command line.
190 * For etINT, etREAL and etCHAR an extra argument is read (when present)
191 * for etBOOL the gmx_boolean option is changed to the negate value
193 static void get_pargs(int *argc, char *argv[], int nparg, t_pargs pa[])
200 snew(bKeep, *argc+1);
204 for (i = 1; (i < *argc); i++)
207 for (j = 0; (j < nparg); j++)
209 if (pa[j].type == etBOOL)
211 sprintf(buf, "-no%s", pa[j].option+1);
212 if (strcmp(pa[j].option, argv[i]) == 0)
218 else if (strcmp(buf, argv[i]) == 0)
225 else if (strcmp(pa[j].option, argv[i]) == 0)
229 fprintf(stderr, "Setting option %s more than once!\n",
237 *pa[j].u.i = iscan(*argc, argv, &i);
240 *pa[j].u.is = istepscan(*argc, argv, &i);
244 *pa[j].u.r = dscan(*argc, argv, &i);
247 *(pa[j].u.c) = sscan(*argc, argv, &i);
251 ptr = sscan(*argc, argv, &i);
252 for (k = 1; (pa[j].u.c[k] != NULL); k++)
254 /* only check ptr against beginning of
256 if (gmx_strncasecmp(ptr, pa[j].u.c[k], strlen(ptr)) == 0)
258 if ( ( match == -1 ) ||
259 ( strlen(pa[j].u.c[k]) <
260 strlen(pa[j].u.c[match]) ) )
268 pa[j].u.c[0] = pa[j].u.c[match];
272 gmx_fatal(FARGS, "Invalid argument %s for option %s",
277 (*pa[j].u.rv)[0] = dscan(*argc, argv, &i);
278 if ( (i+1 == *argc) ||
279 ( (argv[i+1][0] == '-') &&
280 !isdigit(argv[i+1][1]) ) )
289 (*pa[j].u.rv)[1] = dscan(*argc, argv, &i);
290 if ( (i+1 == *argc) ||
291 ( (argv[i+1][0] == '-') &&
292 !isdigit(argv[i+1][1]) ) )
295 "%s: vector must have 1 or 3 real parameters",
299 (*pa[j].u.rv)[2] = dscan(*argc, argv, &i);
303 gmx_fatal(FARGS, "Invalid type %d in pargs", pa[j].type);
305 /* i may be incremented, so set it to not keep */
311 /* Remove used entries */
312 for (i = j = 0; (i <= *argc); i++)
323 int opt2parg_int(const char *option, int nparg, t_pargs pa[])
327 for (i = 0; (i < nparg); i++)
329 if (strcmp(pa[i].option, option) == 0)
335 gmx_fatal(FARGS, "No integer option %s in pargs", option);
340 gmx_bool opt2parg_bool(const char *option, int nparg, t_pargs pa[])
344 for (i = 0; (i < nparg); i++)
346 if (strcmp(pa[i].option, option) == 0)
352 gmx_fatal(FARGS, "No boolean option %s in pargs", option);
357 real opt2parg_real(const char *option, int nparg, t_pargs pa[])
361 for (i = 0; (i < nparg); i++)
363 if (strcmp(pa[i].option, option) == 0)
369 gmx_fatal(FARGS, "No real option %s in pargs", option);
374 const char *opt2parg_str(const char *option, int nparg, t_pargs pa[])
378 for (i = 0; (i < nparg); i++)
380 if (strcmp(pa[i].option, option) == 0)
386 gmx_fatal(FARGS, "No string option %s in pargs", option);
391 gmx_bool opt2parg_bSet(const char *option, int nparg, t_pargs pa[])
395 for (i = 0; (i < nparg); i++)
397 if (strcmp(pa[i].option, option) == 0)
403 gmx_fatal(FARGS, "No such option %s in pargs", option);
405 return FALSE; /* Too make some compilers happy */
408 const char *opt2parg_enum(const char *option, int nparg, t_pargs pa[])
412 for (i = 0; (i < nparg); i++)
414 if (strcmp(pa[i].option, option) == 0)
420 gmx_fatal(FARGS, "No such option %s in pargs", option);
425 /********************************************************************
426 * parse_common_args()
429 static void set_default_time_unit(const char *time_list[], gmx_bool bCanTime)
432 const char *select = NULL;
436 select = getenv("GMXTIMEUNIT");
440 while (time_list[i] && strcmp(time_list[i], select) != 0)
446 if (!bCanTime || select == NULL ||
447 time_list[i] == NULL || strcmp(time_list[i], select) != 0)
449 /* Set it to the default: ps */
451 while (time_list[i] && strcmp(time_list[i], "ps") != 0)
457 time_list[0] = time_list[i];
460 static void set_default_xvg_format(const char *xvg_list[])
465 select = getenv("GMX_VIEW_XVG");
468 /* The default is the first option */
469 xvg_list[0] = xvg_list[1];
474 while (xvg_list[i] && strcmp(xvg_list[i], select) != 0)
478 if (xvg_list[i] != NULL)
480 xvg_list[0] = xvg_list[i];
484 xvg_list[0] = xvg_list[exvgNONE];
489 static int add_parg(int npargs, t_pargs *pa, t_pargs *pa_add)
491 memcpy(&(pa[npargs]), pa_add, sizeof(*pa_add));
503 * Converts a t_filenm option into an Options option.
505 * \param options Options object to add the new option to.
506 * \param[in] fnm t_filenm option to convert.
508 * \ingroup module_commandline
510 void filenmToOptions(Options *options, const t_filenm *fnm)
512 const bool bRead = ((fnm->flag & ffREAD) != 0);
513 const bool bWrite = ((fnm->flag & ffWRITE) != 0);
514 const bool bOptional = ((fnm->flag & ffOPT) != 0);
515 const bool bLibrary = ((fnm->flag & ffLIB) != 0);
516 const bool bMultiple = ((fnm->flag & ffMULT) != 0);
517 const char *const name = &fnm->opt[1];
518 const char * defName = fnm->fn;
521 defName = ftp2defnm(fnm->ftp);
523 // Since we are not (yet) using this for actual parsing, we don't need to
526 FileNameOption(name).defaultBasename(defName).legacyType(fnm->ftp)
527 .readWriteFlags(bRead, bWrite).required(!bOptional)
528 .libraryFile(bLibrary).multiValue(bMultiple)
529 .description(ftp2desc(fnm->ftp)));
533 * Converts a t_pargs option into an Options option.
535 * \param options Options object to add the new option to.
536 * \param[in] pa t_pargs option to convert.
538 * \ingroup module_commandline
540 void pargsToOptions(Options *options, t_pargs *pa)
542 const bool bHidden = is_hidden(pa);
543 const char *const name = &pa->option[1];
544 const char *const desc = (bHidden ? &pa->desc[6] : pa->desc);
545 // Since we are not (yet) using this for actual parsing, we can take some
546 // shortcuts and not set any storage where there is no direct
547 // correspondence in the types.
552 IntegerOption(name).store(pa->u.i)
553 .description(desc).hidden(bHidden));
557 Int64Option(name).store(pa->u.is)
558 .description(desc).hidden(bHidden));
562 RealOption(name).store(pa->u.r)
563 .description(desc).hidden(bHidden));
567 RealOption(name).store(pa->u.r).timeValue()
568 .description(desc).hidden(bHidden));
572 const char *const defValue = (*pa->u.c != NULL ? *pa->u.c : "");
574 StringOption(name).defaultValue(defValue)
575 .description(desc).hidden(bHidden));
580 BooleanOption(name).defaultValue(*pa->u.b)
581 .description(desc).hidden(bHidden));
585 RealOption(name).store(*pa->u.rv).vector()
586 .description(desc).hidden(bHidden));
590 StringOption(name).defaultEnumIndex(nenum(pa->u.c) - 1)
591 .enumValueFromNullTerminatedArray(pa->u.c + 1)
592 .description(desc).hidden(bHidden));
595 GMX_THROW(NotImplementedError("Argument type not implemented"));
602 gmx_bool parse_common_args(int *argc, char *argv[], unsigned long Flags,
603 int nfile, t_filenm fnm[], int npargs, t_pargs *pa,
604 int ndesc, const char **desc,
605 int nbugs, const char **bugs,
608 /* This array should match the order of the enum in oenv.h */
609 const char *xvg_format[] = { NULL, "xmgrace", "xmgr", "none", NULL };
610 /* This array should match the order of the enum in oenv.h */
611 const char *time_units[] = {
612 NULL, "fs", "ps", "ns", "us", "ms", "s",
615 int nicelevel = 0, debug_level = 0;
617 real tbegin = 0, tend = 0, tdelta = 0;
618 gmx_bool bView = FALSE;
620 t_pargs *all_pa = NULL;
625 "-npri", FALSE, etINT, {&npri},
626 "HIDDEN Set non blocking priority (try 128)"
630 "-nice", FALSE, etINT, {&nicelevel},
633 t_pargs deffnm_pa = {
634 "-deffnm", FALSE, etSTR, {&deffnm},
635 "Set the default filename for all file options"
638 "-b", FALSE, etTIME, {&tbegin},
639 "First frame (%t) to read from trajectory"
642 "-e", FALSE, etTIME, {&tend},
643 "Last frame (%t) to read from trajectory"
646 "-dt", FALSE, etTIME, {&tdelta},
647 "Only use frame when t MOD dt = first time (%t)"
650 "-w", FALSE, etBOOL, {&bView},
651 "View output [TT].xvg[tt], [TT].xpm[tt], [TT].eps[tt] and [TT].pdb[tt] files"
654 "-xvg", FALSE, etENUM, {xvg_format},
655 "xvg plot formatting"
658 "-tu", FALSE, etENUM, {time_units},
661 /* Maximum number of extra arguments */
665 { "-debug", FALSE, etINT, {&debug_level},
666 "HIDDENWrite file with debug information, 1: short, 2: also x and f" },
668 #define NPCA_PA asize(pca_pa)
670 int i, j, k, npall, max_pa;
672 // Handle the flags argument, which is a bit field
673 // The FF macro returns whether or not the bit is set
674 #define FF(arg) ((Flags & arg) == arg)
676 /* Check for double arguments */
677 for (i = 1; (i < *argc); i++)
679 if (argv[i] && (strlen(argv[i]) > 1) && (!std::isdigit(argv[i][1])))
681 for (j = i+1; (j < *argc); j++)
683 if ( (argv[i][0] == '-') && (argv[j][0] == '-') &&
684 (strcmp(argv[i], argv[j]) == 0) )
686 if (FF(PCA_NOEXIT_ON_ARGS))
688 fprintf(stderr, "Double command line argument %s\n",
693 gmx_fatal(FARGS, "Double command line argument %s\n",
702 /* Check ALL the flags ... */
703 max_pa = NPCA_PA + EXTRA_PA + npargs+1;
704 snew(all_pa, max_pa);
706 for (i = npall = 0; (i < static_cast<int>(NPCA_PA)); i++)
708 npall = add_parg(npall, all_pa, &(pca_pa[i]));
712 const char *envstr = getenv("GMXNPRIALL");
715 npri = strtol(envstr, NULL, 10);
719 envstr = getenv("GMXNPRI");
722 npri = strtol(envstr, NULL, 10);
725 npall = add_parg(npall, all_pa, &npri_pa);
732 npall = add_parg(npall, all_pa, &nice_pa);
734 if (FF(PCA_CAN_SET_DEFFNM))
736 npall = add_parg(npall, all_pa, &deffnm_pa);
738 if (FF(PCA_CAN_BEGIN))
740 npall = add_parg(npall, all_pa, &begin_pa);
744 npall = add_parg(npall, all_pa, &end_pa);
748 npall = add_parg(npall, all_pa, &dt_pa);
750 if (FF(PCA_TIME_UNIT))
752 npall = add_parg(npall, all_pa, &time_pa);
754 if (FF(PCA_CAN_VIEW))
756 npall = add_parg(npall, all_pa, &view_pa);
760 for (i = 0; (i < nfile); i++)
762 bXvgr = bXvgr || (fnm[i].ftp == efXVG);
766 npall = add_parg(npall, all_pa, &xvg_pa);
769 /* Now append the program specific arguments */
770 for (i = 0; (i < npargs); i++)
772 npall = add_parg(npall, all_pa, &(pa[i]));
775 /* set etENUM options to default */
776 for (i = 0; (i < npall); i++)
778 if (all_pa[i].type == etENUM)
780 all_pa[i].u.c[0] = all_pa[i].u.c[1];
783 set_default_time_unit(time_units, FF(PCA_TIME_UNIT));
784 set_default_xvg_format(xvg_format);
786 /* Now parse all the command-line options */
787 get_pargs(argc, argv, npall, all_pa);
789 /* set program name, command line, and default values for output options */
790 output_env_init(oenv, gmx::getProgramContext(), (time_unit_t)nenum(time_units), bView,
791 (xvg_format_t)nenum(xvg_format), 0, debug_level);
793 /* Parse the file args */
794 parse_file_args(argc, argv, nfile, fnm, deffnm, !FF(PCA_NOT_READ_NODE));
796 /* Open the debug file */
801 if (gmx_mpi_initialized())
803 sprintf(buf, "%s%d.debug", output_env_get_short_program_name(*oenv),
808 sprintf(buf, "%s.debug", output_env_get_short_program_name(*oenv));
811 init_debug(debug_level, buf);
812 fprintf(stderr, "Opening debug file %s (src code file %s, line %d)\n",
813 buf, __FILE__, __LINE__);
816 /* Now copy the results back... */
817 for (i = 0, k = npall-npargs; (i < npargs); i++, k++)
819 memcpy(&(pa[i]), &(all_pa[k]), (size_t)sizeof(pa[i]));
822 #if (defined __sgi && USE_SGI_FPE)
829 const gmx::CommandLineHelpContext *context =
830 gmx::GlobalCommandLineHelpContext::get();
831 bExit = (context != NULL);
832 if (context != NULL && !(FF(PCA_QUIET)))
834 gmx::Options options(NULL, NULL);
835 options.setDescription(gmx::ConstArrayRef<const char *>(desc, ndesc));
836 for (i = 0; i < nfile; i++)
838 gmx::filenmToOptions(&options, &fnm[i]);
840 for (i = 0; i < npall; i++)
842 gmx::pargsToOptions(&options, &all_pa[i]);
844 gmx::CommandLineHelpWriter(options)
845 .setShowDescriptions(true)
846 .setTimeUnitString(output_env_get_time_unit(*oenv))
847 .setKnownIssues(gmx::ConstArrayRef<const char *>(bugs, nbugs))
848 .writeHelp(*context);
851 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
853 /* Set the nice level */
855 if (npri != 0 && !bExit)
857 schedctl(MPTS_RTPRI, 0, npri);
863 /* The some system, e.g. the catamount kernel on cray xt3 do not have nice(2). */
864 if (nicelevel != 0 && !bExit)
866 static gmx_bool nice_set = FALSE; /* only set it once */
867 static tMPI_Thread_mutex_t init_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
868 tMPI_Thread_mutex_lock(&init_mutex);
871 if (nice(nicelevel) == -1)
873 /* Do nothing, but use the return value to avoid warnings. */
877 tMPI_Thread_mutex_unlock(&init_mutex);
882 /* convert time options, must be done after printing! */
884 for (i = 0; i < npall; i++)
886 if (all_pa[i].type == etTIME && all_pa[i].bSet)
888 *all_pa[i].u.r *= output_env_get_time_invfactor(*oenv);
892 /* Extract Time info from arguments */
893 if (FF(PCA_CAN_BEGIN) && opt2parg_bSet("-b", npall, all_pa))
895 setTimeValue(TBEGIN, opt2parg_real("-b", npall, all_pa));
898 if (FF(PCA_CAN_END) && opt2parg_bSet("-e", npall, all_pa))
900 setTimeValue(TEND, opt2parg_real("-e", npall, all_pa));
903 if (FF(PCA_CAN_DT) && opt2parg_bSet("-dt", npall, all_pa))
905 setTimeValue(TDELTA, opt2parg_real("-dt", npall, all_pa));
911 if (!FF(PCA_NOEXIT_ON_ARGS))