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