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