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