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