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