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