Remove dependency on commandline/ from oenv.cpp
[alexxy/gromacs.git] / src / gromacs / commandline / pargs.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 /* This file is completely threadsafe - keep it that way! */
38 #include "gromacs/commandline/pargs.h"
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #include <cctype>
45 #include <cstdio>
46 #include <cstdlib>
47 #include <cstring>
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52
53 /* used for npri */
54 #ifdef __sgi
55 #include <sys/schedctl.h>
56 #include <sys/sysmp.h>
57 #endif
58
59 #include "thread_mpi/threads.h"
60
61 #include "gromacs/legacyheaders/gmx_fatal.h"
62 #include "gromacs/legacyheaders/macros.h"
63 #include "gromacs/legacyheaders/network.h"
64 #include "gromacs/legacyheaders/smalloc.h"
65 #include "gromacs/legacyheaders/string2.h"
66
67 #include "gromacs/commandline/cmdlinehelpcontext.h"
68 #include "gromacs/commandline/cmdlinehelpwriter.h"
69 #include "gromacs/commandline/shellcompletions.h"
70 #include "gromacs/fileio/timecontrol.h"
71 #include "gromacs/options/basicoptions.h"
72 #include "gromacs/options/filenameoption.h"
73 #include "gromacs/options/options.h"
74 #include "gromacs/utility/arrayref.h"
75 #include "gromacs/utility/exceptions.h"
76 #include "gromacs/utility/gmxassert.h"
77 #include "gromacs/utility/programcontext.h"
78 #include "gromacs/utility/stringutil.h"
79
80 /* The source code in this file should be thread-safe.
81       Please keep it that way. */
82
83 static void usage(const char *type, const char *arg)
84 {
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);
87 }
88
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.
94  */
95 static int iscan(int argc, char *argv[], int *i)
96 {
97     const char *const arg = argv[*i];
98     if (argc <= (*i)+1)
99     {
100         usage("an integer", arg);
101     }
102     const char *const value = argv[++(*i)];
103     char             *endptr;
104     int               var = std::strtol(value, &endptr, 10);
105     if (*value == '\0' || *endptr != '\0')
106     {
107         usage("an integer", arg);
108     }
109     return var;
110 }
111
112 /* Same as above, but for large integer values */
113 static gmx_int64_t istepscan(int argc, char *argv[], int *i)
114 {
115     const char *const arg = argv[*i];
116     if (argc <= (*i)+1)
117     {
118         usage("an integer", arg);
119     }
120     const char *const value = argv[++(*i)];
121     char             *endptr;
122     gmx_int64_t       var = str_to_int64_t(value, &endptr);
123     if (*value == '\0' || *endptr != '\0')
124     {
125         usage("an integer", arg);
126     }
127     return var;
128 }
129
130 /* Routine similar to the above, but working on doubles. */
131 static double dscan(int argc, char *argv[], int *i)
132 {
133     const char *const arg = argv[*i];
134     if (argc <= (*i)+1)
135     {
136         usage("a real", arg);
137     }
138     const char *const value = argv[++(*i)];
139     char             *endptr;
140     double            var = std::strtod(value, &endptr);
141     if (*value == '\0' || *endptr != '\0')
142     {
143         usage("a real", arg);
144     }
145     return var;
146 }
147
148 /* Routine similar to the above, but working on strings. The pointer
149  * returned is a pointer to the argv field.
150  */
151 static char *sscan(int argc, char *argv[], int *i)
152 {
153     if (argc > (*i)+1)
154     {
155         if ( (argv[(*i)+1][0] == '-') && (argc > (*i)+2) &&
156              (argv[(*i)+2][0] != '-') )
157         {
158             fprintf(stderr, "Possible missing string argument for option %s\n\n",
159                     argv[*i]);
160         }
161     }
162     else
163     {
164         usage("a string", argv[*i]);
165     }
166
167     return argv[++(*i)];
168 }
169
170 static gmx_bool is_hidden(t_pargs *pa)
171 {
172     return (strstr(pa->desc, "HIDDEN") != NULL);
173 }
174
175 int nenum(const char *const enumc[])
176 {
177     int i;
178
179     i = 1;
180     /* we *can* compare pointers directly here! */
181     while (enumc[i] && enumc[0] != enumc[i])
182     {
183         i++;
184     }
185
186     return i;
187 }
188
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
192  */
193 static void get_pargs(int *argc, char *argv[], int nparg, t_pargs pa[])
194 {
195     int       i, j, k, match;
196     gmx_bool *bKeep;
197     char      buf[32];
198     char     *ptr;
199
200     snew(bKeep, *argc+1);
201     bKeep[0]     = TRUE;
202     bKeep[*argc] = TRUE;
203
204     for (i = 1; (i < *argc); i++)
205     {
206         bKeep[i] = TRUE;
207         for (j = 0; (j < nparg); j++)
208         {
209             if (pa[j].type == etBOOL)
210             {
211                 sprintf(buf, "-no%s", pa[j].option+1);
212                 if (strcmp(pa[j].option, argv[i]) == 0)
213                 {
214                     *pa[j].u.b = TRUE;
215                     pa[j].bSet = TRUE;
216                     bKeep[i]   = FALSE;
217                 }
218                 else if (strcmp(buf, argv[i]) == 0)
219                 {
220                     *pa[j].u.b = FALSE;
221                     pa[j].bSet = TRUE;
222                     bKeep[i]   = FALSE;
223                 }
224             }
225             else if (strcmp(pa[j].option, argv[i]) == 0)
226             {
227                 if (pa[j].bSet)
228                 {
229                     fprintf(stderr, "Setting option %s more than once!\n",
230                             pa[j].option);
231                 }
232                 pa[j].bSet = TRUE;
233                 bKeep[i]   = FALSE;
234                 switch (pa[j].type)
235                 {
236                     case etINT:
237                         *pa[j].u.i = iscan(*argc, argv, &i);
238                         break;
239                     case etINT64:
240                         *pa[j].u.is = istepscan(*argc, argv, &i);
241                         break;
242                     case etTIME:
243                     case etREAL:
244                         *pa[j].u.r = dscan(*argc, argv, &i);
245                         break;
246                     case etSTR:
247                         *(pa[j].u.c) = sscan(*argc, argv, &i);
248                         break;
249                     case etENUM:
250                         match = -1;
251                         ptr   = sscan(*argc, argv, &i);
252                         for (k = 1; (pa[j].u.c[k] != NULL); k++)
253                         {
254                             /* only check ptr against beginning of
255                                pa[j].u.c[k] */
256                             if (gmx_strncasecmp(ptr, pa[j].u.c[k], strlen(ptr)) == 0)
257                             {
258                                 if ( ( match == -1 ) ||
259                                      ( strlen(pa[j].u.c[k]) <
260                                        strlen(pa[j].u.c[match]) ) )
261                                 {
262                                     match = k;
263                                 }
264                             }
265                         }
266                         if (match != -1)
267                         {
268                             pa[j].u.c[0] = pa[j].u.c[match];
269                         }
270                         else
271                         {
272                             gmx_fatal(FARGS, "Invalid argument %s for option %s",
273                                       ptr, pa[j].option);
274                         }
275                         break;
276                     case etRVEC:
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]) ) )
281                         {
282                             (*pa[j].u.rv)[1]     =
283                                 (*pa[j].u.rv)[2] =
284                                     (*pa[j].u.rv)[0];
285                         }
286                         else
287                         {
288                             bKeep[i]         = FALSE;
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]) ) )
293                             {
294                                 gmx_fatal(FARGS,
295                                           "%s: vector must have 1 or 3 real parameters",
296                                           pa[j].option);
297                             }
298                             bKeep[i]         = FALSE;
299                             (*pa[j].u.rv)[2] = dscan(*argc, argv, &i);
300                         }
301                         break;
302                     default:
303                         gmx_fatal(FARGS, "Invalid type %d in pargs", pa[j].type);
304                 }
305                 /* i may be incremented, so set it to not keep */
306                 bKeep[i] = FALSE;
307             }
308         }
309     }
310
311     /* Remove used entries */
312     for (i = j = 0; (i <= *argc); i++)
313     {
314         if (bKeep[i])
315         {
316             argv[j++] = argv[i];
317         }
318     }
319     (*argc) = j-1;
320     sfree(bKeep);
321 }
322
323 int opt2parg_int(const char *option, int nparg, t_pargs pa[])
324 {
325     int i;
326
327     for (i = 0; (i < nparg); i++)
328     {
329         if (strcmp(pa[i].option, option) == 0)
330         {
331             return *pa[i].u.i;
332         }
333     }
334
335     gmx_fatal(FARGS, "No integer option %s in pargs", option);
336
337     return 0;
338 }
339
340 gmx_bool opt2parg_bool(const char *option, int nparg, t_pargs pa[])
341 {
342     int i;
343
344     for (i = 0; (i < nparg); i++)
345     {
346         if (strcmp(pa[i].option, option) == 0)
347         {
348             return *pa[i].u.b;
349         }
350     }
351
352     gmx_fatal(FARGS, "No boolean option %s in pargs", option);
353
354     return FALSE;
355 }
356
357 real opt2parg_real(const char *option, int nparg, t_pargs pa[])
358 {
359     int i;
360
361     for (i = 0; (i < nparg); i++)
362     {
363         if (strcmp(pa[i].option, option) == 0)
364         {
365             return *pa[i].u.r;
366         }
367     }
368
369     gmx_fatal(FARGS, "No real option %s in pargs", option);
370
371     return 0.0;
372 }
373
374 const char *opt2parg_str(const char *option, int nparg, t_pargs pa[])
375 {
376     int i;
377
378     for (i = 0; (i < nparg); i++)
379     {
380         if (strcmp(pa[i].option, option) == 0)
381         {
382             return *(pa[i].u.c);
383         }
384     }
385
386     gmx_fatal(FARGS, "No string option %s in pargs", option);
387
388     return NULL;
389 }
390
391 gmx_bool opt2parg_bSet(const char *option, int nparg, t_pargs pa[])
392 {
393     int i;
394
395     for (i = 0; (i < nparg); i++)
396     {
397         if (strcmp(pa[i].option, option) == 0)
398         {
399             return pa[i].bSet;
400         }
401     }
402
403     gmx_fatal(FARGS, "No such option %s in pargs", option);
404
405     return FALSE; /* Too make some compilers happy */
406 }
407
408 const char *opt2parg_enum(const char *option, int nparg, t_pargs pa[])
409 {
410     int i;
411
412     for (i = 0; (i < nparg); i++)
413     {
414         if (strcmp(pa[i].option, option) == 0)
415         {
416             return pa[i].u.c[0];
417         }
418     }
419
420     gmx_fatal(FARGS, "No such option %s in pargs", option);
421
422     return NULL;
423 }
424
425 /********************************************************************
426  * parse_common_args()
427  */
428
429 static void set_default_time_unit(const char *time_list[], gmx_bool bCanTime)
430 {
431     int         i      = 0;
432     const char *select = NULL;
433
434     if (bCanTime)
435     {
436         select = getenv("GMXTIMEUNIT");
437         if (select != NULL)
438         {
439             i = 1;
440             while (time_list[i] && strcmp(time_list[i], select) != 0)
441             {
442                 i++;
443             }
444         }
445     }
446     if (!bCanTime || select == NULL ||
447         time_list[i] == NULL || strcmp(time_list[i], select) != 0)
448     {
449         /* Set it to the default: ps */
450         i = 1;
451         while (time_list[i] && strcmp(time_list[i], "ps") != 0)
452         {
453             i++;
454         }
455
456     }
457     time_list[0] = time_list[i];
458 }
459
460 static void set_default_xvg_format(const char *xvg_list[])
461 {
462     int         i;
463     const char *select;
464
465     select = getenv("GMX_VIEW_XVG");
466     if (select == NULL)
467     {
468         /* The default is the first option */
469         xvg_list[0] = xvg_list[1];
470     }
471     else
472     {
473         i = 1;
474         while (xvg_list[i] && strcmp(xvg_list[i], select) != 0)
475         {
476             i++;
477         }
478         if (xvg_list[i] != NULL)
479         {
480             xvg_list[0] = xvg_list[i];
481         }
482         else
483         {
484             xvg_list[0] = xvg_list[exvgNONE];
485         }
486     }
487 }
488
489 static int add_parg(int npargs, t_pargs *pa, t_pargs *pa_add)
490 {
491     memcpy(&(pa[npargs]), pa_add, sizeof(*pa_add));
492
493     return npargs+1;
494 }
495
496 namespace gmx
497 {
498
499 namespace
500 {
501
502 /*! \brief
503  * Converts a t_filenm option into an Options option.
504  *
505  * \param     options Options object to add the new option to.
506  * \param[in] fnm     t_filenm option to convert.
507  *
508  * \ingroup module_commandline
509  */
510 void filenmToOptions(Options *options, const t_filenm *fnm)
511 {
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;
519     if (defName == NULL)
520     {
521         defName = ftp2defnm(fnm->ftp);
522     }
523     // Since we are not (yet) using this for actual parsing, we don't need to
524     // set any storage.
525     options->addOption(
526             FileNameOption(name).defaultBasename(defName).legacyType(fnm->ftp)
527                 .readWriteFlags(bRead, bWrite).required(!bOptional)
528                 .libraryFile(bLibrary).multiValue(bMultiple)
529                 .description(ftp2desc(fnm->ftp)));
530 }
531
532 /*! \brief
533  * Converts a t_pargs option into an Options option.
534  *
535  * \param     options Options object to add the new option to.
536  * \param[in] pa      t_pargs option to convert.
537  *
538  * \ingroup module_commandline
539  */
540 void pargsToOptions(Options *options, t_pargs *pa)
541 {
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.
548     switch (pa->type)
549     {
550         case etINT:
551             options->addOption(
552                 IntegerOption(name).store(pa->u.i)
553                     .description(desc).hidden(bHidden));
554             return;
555         case etINT64:
556             options->addOption(
557                 Int64Option(name).store(pa->u.is)
558                     .description(desc).hidden(bHidden));
559             return;
560         case etREAL:
561             options->addOption(
562                 RealOption(name).store(pa->u.r)
563                     .description(desc).hidden(bHidden));
564             return;
565         case etTIME:
566             options->addOption(
567                 RealOption(name).store(pa->u.r).timeValue()
568                     .description(desc).hidden(bHidden));
569             return;
570         case etSTR:
571         {
572             const char *const defValue = (*pa->u.c != NULL ? *pa->u.c : "");
573             options->addOption(
574                     StringOption(name).defaultValue(defValue)
575                         .description(desc).hidden(bHidden));
576             return;
577         }
578         case etBOOL:
579             options->addOption(
580                 BooleanOption(name).defaultValue(*pa->u.b)
581                     .description(desc).hidden(bHidden));
582             return;
583         case etRVEC:
584             options->addOption(
585                 RealOption(name).store(*pa->u.rv).vector()
586                     .description(desc).hidden(bHidden));
587             return;
588         case etENUM:
589             options->addOption(
590                 StringOption(name).defaultEnumIndex(nenum(pa->u.c) - 1)
591                     .enumValueFromNullTerminatedArray(pa->u.c + 1)
592                     .description(desc).hidden(bHidden));
593             return;
594     }
595     GMX_THROW(NotImplementedError("Argument type not implemented"));
596 }
597
598 } // namespace
599
600 } // namespace gmx
601
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,
606                            output_env_t *oenv)
607 {
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",
613         NULL
614     };
615     int         nicelevel = 0, debug_level = 0;
616     char       *deffnm    = NULL;
617     real        tbegin    = 0, tend = 0, tdelta = 0;
618     gmx_bool    bView     = FALSE;
619
620     t_pargs    *all_pa = NULL;
621
622 #ifdef __sgi
623     int     npri      = 0;
624     t_pargs npri_pa   = {
625         "-npri", FALSE, etINT,   {&npri},
626         "HIDDEN Set non blocking priority (try 128)"
627     };
628 #endif
629     t_pargs nice_pa   = {
630         "-nice", FALSE, etINT,   {&nicelevel},
631         "Set the nicelevel"
632     };
633     t_pargs deffnm_pa = {
634         "-deffnm", FALSE, etSTR, {&deffnm},
635         "Set the default filename for all file options"
636     };
637     t_pargs begin_pa  = {
638         "-b",    FALSE, etTIME,  {&tbegin},
639         "First frame (%t) to read from trajectory"
640     };
641     t_pargs end_pa    = {
642         "-e",    FALSE, etTIME,  {&tend},
643         "Last frame (%t) to read from trajectory"
644     };
645     t_pargs dt_pa     = {
646         "-dt",   FALSE, etTIME,  {&tdelta},
647         "Only use frame when t MOD dt = first time (%t)"
648     };
649     t_pargs view_pa   = {
650         "-w",    FALSE, etBOOL,  {&bView},
651         "View output [TT].xvg[tt], [TT].xpm[tt], [TT].eps[tt] and [TT].pdb[tt] files"
652     };
653     t_pargs xvg_pa    = {
654         "-xvg",  FALSE, etENUM,  {xvg_format},
655         "xvg plot formatting"
656     };
657     t_pargs time_pa   = {
658         "-tu",   FALSE, etENUM,  {time_units},
659         "Time unit"
660     };
661     /* Maximum number of extra arguments */
662 #define EXTRA_PA 16
663
664     t_pargs  pca_pa[] = {
665         { "-debug", FALSE, etINT, {&debug_level},
666           "HIDDENWrite file with debug information, 1: short, 2: also x and f" },
667     };
668 #define NPCA_PA asize(pca_pa)
669     gmx_bool bXvgr;
670     int      i, j, k, npall, max_pa;
671
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)
675
676     /* Check for double arguments */
677     for (i = 1; (i < *argc); i++)
678     {
679         if (argv[i] && (strlen(argv[i]) > 1) && (!std::isdigit(argv[i][1])))
680         {
681             for (j = i+1; (j < *argc); j++)
682             {
683                 if ( (argv[i][0] == '-') && (argv[j][0] == '-') &&
684                      (strcmp(argv[i], argv[j]) == 0) )
685                 {
686                     if (FF(PCA_NOEXIT_ON_ARGS))
687                     {
688                         fprintf(stderr, "Double command line argument %s\n",
689                                 argv[i]);
690                     }
691                     else
692                     {
693                         gmx_fatal(FARGS, "Double command line argument %s\n",
694                                   argv[i]);
695                     }
696                 }
697             }
698         }
699     }
700     debug_gmx();
701
702     /* Check ALL the flags ... */
703     max_pa = NPCA_PA + EXTRA_PA + npargs+1;
704     snew(all_pa, max_pa);
705
706     for (i = npall = 0; (i < static_cast<int>(NPCA_PA)); i++)
707     {
708         npall = add_parg(npall, all_pa, &(pca_pa[i]));
709     }
710
711 #ifdef __sgi
712     const char *envstr = getenv("GMXNPRIALL");
713     if (envstr)
714     {
715         npri = strtol(envstr, NULL, 10);
716     }
717     if (FF(PCA_BE_NICE))
718     {
719         envstr = getenv("GMXNPRI");
720         if (envstr)
721         {
722             npri = strtol(envstr, NULL, 10);
723         }
724     }
725     npall = add_parg(npall, all_pa, &npri_pa);
726 #endif
727
728     if (FF(PCA_BE_NICE))
729     {
730         nicelevel = 19;
731     }
732     npall = add_parg(npall, all_pa, &nice_pa);
733
734     if (FF(PCA_CAN_SET_DEFFNM))
735     {
736         npall = add_parg(npall, all_pa, &deffnm_pa);
737     }
738     if (FF(PCA_CAN_BEGIN))
739     {
740         npall = add_parg(npall, all_pa, &begin_pa);
741     }
742     if (FF(PCA_CAN_END))
743     {
744         npall = add_parg(npall, all_pa, &end_pa);
745     }
746     if (FF(PCA_CAN_DT))
747     {
748         npall = add_parg(npall, all_pa, &dt_pa);
749     }
750     if (FF(PCA_TIME_UNIT))
751     {
752         npall = add_parg(npall, all_pa, &time_pa);
753     }
754     if (FF(PCA_CAN_VIEW))
755     {
756         npall = add_parg(npall, all_pa, &view_pa);
757     }
758
759     bXvgr = FALSE;
760     for (i = 0; (i < nfile); i++)
761     {
762         bXvgr = bXvgr ||  (fnm[i].ftp == efXVG);
763     }
764     if (bXvgr)
765     {
766         npall = add_parg(npall, all_pa, &xvg_pa);
767     }
768
769     /* Now append the program specific arguments */
770     for (i = 0; (i < npargs); i++)
771     {
772         npall = add_parg(npall, all_pa, &(pa[i]));
773     }
774
775     /* set etENUM options to default */
776     for (i = 0; (i < npall); i++)
777     {
778         if (all_pa[i].type == etENUM)
779         {
780             all_pa[i].u.c[0] = all_pa[i].u.c[1];
781         }
782     }
783     set_default_time_unit(time_units, FF(PCA_TIME_UNIT));
784     set_default_xvg_format(xvg_format);
785
786     /* Now parse all the command-line options */
787     get_pargs(argc, argv, npall, all_pa);
788
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);
792
793     /* Parse the file args */
794     parse_file_args(argc, argv, nfile, fnm, deffnm, !FF(PCA_NOT_READ_NODE));
795
796     /* Open the debug file */
797     if (debug_level > 0)
798     {
799         char buf[256];
800
801         if (gmx_mpi_initialized())
802         {
803             sprintf(buf, "%s%d.debug", output_env_get_short_program_name(*oenv),
804                     gmx_node_rank());
805         }
806         else
807         {
808             sprintf(buf, "%s.debug", output_env_get_short_program_name(*oenv));
809         }
810
811         init_debug(debug_level, buf);
812         fprintf(stderr, "Opening debug file %s (src code file %s, line %d)\n",
813                 buf, __FILE__, __LINE__);
814     }
815
816     /* Now copy the results back... */
817     for (i = 0, k = npall-npargs; (i < npargs); i++, k++)
818     {
819         memcpy(&(pa[i]), &(all_pa[k]), (size_t)sizeof(pa[i]));
820     }
821
822 #if (defined __sgi && USE_SGI_FPE)
823     doexceptions();
824 #endif
825
826     bool bExit = false;
827     try
828     {
829         const gmx::CommandLineHelpContext *context =
830             gmx::GlobalCommandLineHelpContext::get();
831         bExit = (context != NULL);
832         if (context != NULL && !(FF(PCA_QUIET)))
833         {
834             gmx::Options options(NULL, NULL);
835             options.setDescription(gmx::ConstArrayRef<const char *>(desc, ndesc));
836             for (i = 0; i < nfile; i++)
837             {
838                 gmx::filenmToOptions(&options, &fnm[i]);
839             }
840             for (i = 0; i < npall; i++)
841             {
842                 gmx::pargsToOptions(&options, &all_pa[i]);
843             }
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);
849         }
850     }
851     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
852
853     /* Set the nice level */
854 #ifdef __sgi
855     if (npri != 0 && !bExit)
856     {
857         schedctl(MPTS_RTPRI, 0, npri);
858     }
859 #endif
860
861 #ifdef HAVE_UNISTD_H
862 #ifndef GMX_NO_NICE
863     /* The some system, e.g. the catamount kernel on cray xt3 do not have nice(2). */
864     if (nicelevel != 0 && !bExit)
865     {
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);
869         if (!nice_set)
870         {
871             if (nice(nicelevel) == -1)
872             {
873                 /* Do nothing, but use the return value to avoid warnings. */
874             }
875             nice_set = TRUE;
876         }
877         tMPI_Thread_mutex_unlock(&init_mutex);
878     }
879 #endif
880 #endif
881
882     /* convert time options, must be done after printing! */
883
884     for (i = 0; i < npall; i++)
885     {
886         if (all_pa[i].type == etTIME && all_pa[i].bSet)
887         {
888             *all_pa[i].u.r *= output_env_get_time_invfactor(*oenv);
889         }
890     }
891
892     /* Extract Time info from arguments */
893     if (FF(PCA_CAN_BEGIN) && opt2parg_bSet("-b", npall, all_pa))
894     {
895         setTimeValue(TBEGIN, opt2parg_real("-b", npall, all_pa));
896     }
897
898     if (FF(PCA_CAN_END) && opt2parg_bSet("-e", npall, all_pa))
899     {
900         setTimeValue(TEND, opt2parg_real("-e", npall, all_pa));
901     }
902
903     if (FF(PCA_CAN_DT) && opt2parg_bSet("-dt", npall, all_pa))
904     {
905         setTimeValue(TDELTA, opt2parg_real("-dt", npall, all_pa));
906     }
907
908     /* clear memory */
909     sfree(all_pa);
910
911     if (!FF(PCA_NOEXIT_ON_ARGS))
912     {
913         if (*argc > 1)
914         {
915             gmx_cmd(argv[1]);
916         }
917     }
918     return !bExit;
919 #undef FF
920 }