Redefine the default boolean type to gmx_bool.
[alexxy/gromacs.git] / src / gmxlib / filenm.c
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 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <string.h>
40 #include "sysstuff.h"
41 #include "typedefs.h"
42 #include "smalloc.h"
43 #include "string2.h"
44 #include "gmx_fatal.h"
45 #include "filenm.h"
46 #include "futil.h"
47 #include "wman.h"
48 #include "xdrf.h"
49 #include "macros.h"
50
51 #ifdef GMX_THREADS
52 #include "thread_mpi.h"
53 #endif
54
55 /* NOTE: this was a cesspool of thread-unsafe code, has now been 
56  properly proteced by mutexes (hopefully). */
57
58 /* XDR should be available on all platforms now, 
59  * but we keep the possibility of turning it off...
60  */
61 #define USE_XDR
62
63 /* Use bitflag ... */
64 #define IS_SET(fn) ((fn.flag & ffSET) != 0)
65 #define IS_OPT(fn) ((fn.flag & ffOPT) != 0)
66 #define IS_MULT(fn) ((fn.flag & ffMULT) != 0)
67 #define UN_SET(fn) (fn.flag = (fn.flag & ~ffSET))
68 #define DO_SET(fn) (fn.flag = (fn.flag |  ffSET))
69
70 enum
71 {
72     eftASC, eftBIN, eftXDR, eftGEN, eftNR
73 };
74
75 /* To support multiple file types with one general (eg TRX) we have 
76  * these arrays.
77  */
78 static const int trxs[] =
79     {
80 #ifdef USE_XDR 
81         efXTC, efTRR, efCPT,
82 #endif
83         efTRJ, efGRO, efG96, efPDB, efG87 };
84 #define NTRXS asize(trxs)
85
86 static const int tros[] =
87     {
88 #ifdef USE_XDR 
89         efXTC, efTRR,
90 #endif
91         efTRJ, efGRO, efG96, efPDB, efG87 };
92 #define NTROS asize(tros)
93
94 static const int trns[] =
95     {
96 #ifdef USE_XDR
97         efTRR, efCPT,
98 #endif
99         efTRJ };
100 #define NTRNS asize(trns)
101
102 static const int stos[] =
103     { efGRO, efG96, efPDB, efBRK, efENT, efESP, efXYZ };
104 #define NSTOS asize(stos)
105
106 static const int stxs[] =
107     { efGRO, efG96, efPDB, efBRK, efENT, efESP, efXYZ,
108 #ifdef USE_XDR 
109         efTPR,
110 #endif 
111         efTPB, efTPA };
112 #define NSTXS asize(stxs)
113
114 static const int tpxs[] =
115     {
116 #ifdef USE_XDR
117         efTPR,
118 #endif
119         efTPB, efTPA };
120 #define NTPXS asize(tpxs)
121
122 static const int tpss[] =
123     {
124 #ifdef USE_XDR
125         efTPR,
126 #endif
127         efTPB, efTPA, efGRO, efG96, efPDB, efBRK, efENT };
128 #define NTPSS asize(tpss)
129
130 typedef struct
131 {
132     int ftype;
133     const char *ext;
134     const char *defnm;
135     const char *defopt;
136     const char *descr;
137     int ntps;
138     const int *tps;
139 } t_deffile;
140
141 /* this array should correspond to the enum in include/types/filenm.h */
142 static const t_deffile
143     deffile[efNR] =
144 {
145     { eftASC, ".mdp", "grompp", "-f", "grompp input file with MD parameters" },
146     { eftASC, ".gct", "gct",    "-f", "General coupling stuff"},
147     { eftGEN, ".???", "traj", "-f",
148       "Trajectory: xtc trr trj gro g96 pdb cpt", NTRXS, trxs },
149     { eftGEN, ".???", "trajout", "-f",
150       "Trajectory: xtc trr trj gro g96 pdb", NTROS, tros },
151     { eftGEN, ".???", "traj", NULL,
152       "Full precision trajectory: trr trj cpt", NTRNS, trns },
153     { eftXDR, ".trr", "traj", NULL, "Trajectory in portable xdr format" },
154     { eftBIN, ".trj", "traj", NULL, "Trajectory file (architecture specific)" },
155     { eftXDR, ".xtc", "traj", NULL,
156       "Compressed trajectory (portable xdr format)" },
157     { eftASC, ".g87", "gtraj", NULL, "Gromos-87 ASCII trajectory format" },
158     { eftXDR, ".edr", "ener",   NULL, "Energy file"},
159     { eftGEN, ".???", "conf", "-c", "Structure file: gro g96 pdb tpr etc.", 
160       NSTXS, stxs },
161     { eftGEN, ".???", "out", "-o", "Structure file: gro g96 pdb etc.", 
162       NSTOS, stos },
163     { eftASC, ".gro", "conf", "-c", "Coordinate file in Gromos-87 format" },
164     { eftASC, ".g96", "conf", "-c", "Coordinate file in Gromos-96 format" },
165     { eftASC, ".pdb", "eiwit",  "-f", "Protein data bank file"},
166     { eftASC, ".brk", "eiwit",  "-f", "Brookhaven data bank file"},
167     { eftASC, ".ent", "eiwit", "-f", "Entry in the protein date bank" },
168     { eftASC, ".esp", "conf", "-f", "Coordinate file in Espresso format" },
169     { eftASC, ".pqr", "state",  "-o", "Coordinate file for MEAD"},
170     { eftASC, ".xyz", "conf", "-o", "Coordinate file for some other programs" },
171     { eftXDR, ".cpt", "state",  "-cp","Checkpoint file"},
172     { eftASC, ".log", "run",    "-l", "Log file"},
173     { eftASC, ".xvg", "graph",  "-o", "xvgr/xmgr file"},
174     { eftASC, ".out", "hello",  "-o", "Generic output file"},
175     { eftASC, ".ndx", "index",  "-n", "Index file",},
176     { eftASC, ".top", "topol",  "-p", "Topology file"},
177     { eftASC, ".itp", "topinc", NULL, "Include file for topology"},
178     { eftGEN, ".???", "topol", "-s", "Run input file: tpr tpb tpa",
179       NTPXS, tpxs },
180     { eftGEN, ".???", "topol", "-s",
181       "Structure+mass(db): tpr tpb tpa gro g96 pdb", NTPSS, tpss },
182     { eftXDR, ".tpr", "topol",  "-s", "Portable xdr run input file"},
183     { eftASC, ".tpa", "topol",  "-s", "Ascii run input file"},
184     { eftBIN, ".tpb", "topol",  "-s", "Binary run input file"},
185     { eftASC, ".tex", "doc",    "-o", "LaTeX file"},
186     { eftASC, ".rtp", "residue", NULL, "Residue Type file used by pdb2gmx" },
187     { eftASC, ".atp", "atomtp", NULL, "Atomtype file used by pdb2gmx" },
188     { eftASC, ".hdb", "polar",  NULL, "Hydrogen data base"},
189     { eftASC, ".dat", "nnnice", NULL, "Generic data file"},
190     { eftASC, ".dlg", "user",   NULL, "Dialog Box data for ngmx"},
191     { eftASC, ".map", "ss", NULL, "File that maps matrix data to colors" },
192     { eftASC, ".eps", "plot", NULL, "Encapsulated PostScript (tm) file" },
193     { eftASC, ".mat", "ss",     NULL, "Matrix Data file"},
194     { eftASC, ".m2p", "ps",     NULL, "Input file for mat2ps"},
195     { eftXDR, ".mtx", "hessian","-m", "Hessian matrix"},
196     { eftASC, ".edi", "sam",    NULL, "ED sampling input"},
197     { eftASC, ".edo", "sam",    NULL, "ED sampling output"},
198     { eftASC, ".hat", "gk", NULL, "Fourier transform of spread function" },
199     { eftASC, ".cub", "pot",  NULL, "Gaussian cube file" },
200     { eftASC, ".xpm", "root", NULL, "X PixMap compatible matrix file" } 
201 };
202
203 static char *default_file_name = NULL;
204
205 #ifdef GMX_THREADS
206 static tMPI_Thread_mutex_t filenm_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
207 #endif
208
209 #define NZEXT 2
210 const char *z_ext[NZEXT] =
211     { ".gz", ".Z" };
212
213 void set_default_file_name(const char *name)
214 {
215     int i;
216 #ifdef GMX_THREADS
217     tMPI_Thread_mutex_lock(&filenm_mutex);
218 #endif
219     default_file_name = strdup(name);
220 #ifdef GMX_THREADS
221     tMPI_Thread_mutex_unlock(&filenm_mutex);
222 #endif
223
224 #if 0
225     for(i=0; i<efNR; i++)
226     deffile[i].defnm = default_file_name;
227 #endif
228 }
229
230 const char *ftp2ext(int ftp)
231 {
232     if ((0 <= ftp) && (ftp < efNR))
233         return deffile[ftp].ext + 1;
234     else
235         return "unknown";
236 }
237
238 const char *ftp2ext_generic(int ftp)
239 {
240     if ((0 <= ftp) && (ftp < efNR))
241     {
242         switch (ftp)
243         {
244         case efTRX:
245             return "trx";
246         case efTRN:
247             return "trn";
248         case efSTO:
249             return "sto";
250         case efSTX:
251             return "stx";
252         case efTPX:
253             return "tpx";
254         case efTPS:
255             return "tps";
256         default:
257             return ftp2ext(ftp);
258         }
259     }
260     else
261         return "unknown";
262 }
263
264 const char *ftp2desc(int ftp)
265 {
266     if ((0 <= ftp) && (ftp < efNR))
267         return deffile[ftp].descr;
268     else
269         return "unknown filetype";
270 }
271
272 const char *ftp2ftype(int ftp)
273 {
274     if ((ftp >= 0) && (ftp < efNR))
275     {
276         switch (deffile[ftp].ftype)
277         {
278         case eftASC:
279             return "ASCII";
280         case eftBIN:
281             return "Binary";
282         case eftXDR:
283             return "XDR portable";
284         case eftGEN:
285             return "";
286         default:
287             gmx_fatal(FARGS, "Unknown filetype %d in ftp2ftype",deffile[ftp].ftype);
288             break;
289         }
290     }
291     return "unknown";
292 }
293
294 const char *ftp2defnm(int ftp)
295 {
296     const char *buf = NULL;
297
298 #ifdef GMX_THREADS
299     tMPI_Thread_mutex_lock(&filenm_mutex);
300 #endif
301
302     if (default_file_name)
303     {
304         buf = default_file_name;
305     }
306     else
307     {
308         if ((0 <= ftp) && (ftp < efNR))
309         {
310             buf = deffile[ftp].defnm;
311         }
312     }
313 #ifdef GMX_THREADS
314     tMPI_Thread_mutex_unlock(&filenm_mutex);
315 #endif
316
317     return buf;
318 }
319
320 void pr_def(FILE *fp, int ftp)
321 {
322     const t_deffile *df;
323     const char *s = NULL;
324     char *flst, *tmp, *desc;
325     const char *ext;
326     const char *defnm;
327
328     df = &(deffile[ftp]);
329     defnm = ftp2defnm(ftp);
330     /* find default file extension and \tt-ify description */
331     /* FIXME: The constness should not be cast away */
332     flst = (char *) "";
333     desc = strdup(df->descr);
334
335     if (df->ntps)
336     {
337         ext = deffile[df->tps[0]].ext;
338         tmp = strstr(desc, ": ") + 1;
339         if (tmp)
340         {
341             tmp[0] = '\0';
342             tmp++;
343             snew(flst,strlen(tmp)+6);
344             strcpy(flst, " \\tt ");
345             strcat(flst, tmp);
346         }
347     }
348     else
349     {
350         ext = df->ext;
351     }
352     /* now skip dot */
353     if (ext[0])
354         ext++;
355     else
356         ext = "";
357     /* set file contents type */
358     switch (df->ftype)
359     {
360     case eftASC:
361         s = "Asc";
362         break;
363     case eftBIN:
364         s = "Bin";
365         break;
366     case eftXDR:
367         s = "xdr";
368         break;
369     case eftGEN:
370         s = "";
371         break;
372     default:
373         gmx_fatal(FARGS, "Unimplemented filetype %d %d",ftp,
374         df->ftype);
375     }
376     fprintf(fp,"\\tt %8s & \\tt %3s & %3s & \\tt %2s & %s%s \\\\[-0.1ex]\n",
377         defnm, ext, s, df->defopt ? df->defopt : "",
378         check_tex(desc),check_tex(flst));
379     free(desc);
380 }
381
382 void pr_fns(FILE *fp, int nf, const t_filenm tfn[])
383 {
384     int i, f;
385     size_t j;
386     char buf[256], *wbuf, opt_buf[32];
387 #define OPTLEN 4
388 #define NAMELEN 14
389     fprintf(fp, "%6s %12s  %-12s %s\n", "Option", "Filename", "Type",
390             "Description");
391     fprintf(fp,
392             "------------------------------------------------------------\n");
393     for (i = 0; (i < nf); i++)
394     {
395         for (f = 0; (f < tfn[i].nfiles); f++)
396         {
397             sprintf(buf, "%4s %14s  %-12s ", (f == 0) ? tfn[i].opt : "",
398                     tfn[i].fns[f], (f == 0) ? fileopt(tfn[i].flag, opt_buf, 32)
399                         : "");
400             if (f < tfn[i].nfiles - 1)
401                 fprintf(fp, "%s\n", buf);
402         }
403         if (tfn[i].nfiles > 0)
404         {
405             strcat(buf, deffile[tfn[i].ftp].descr);
406             if ((strlen(tfn[i].opt) > OPTLEN)
407                 && (strlen(tfn[i].opt) <= ((OPTLEN + NAMELEN)
408                     - strlen(tfn[i].fns[tfn[i].nfiles - 1]))))
409             {
410                 for (j = strlen(tfn[i].opt); j < strlen(buf)
411                     - (strlen(tfn[i].opt) - OPTLEN) + 1; j++)
412                     buf[j] = buf[j + strlen(tfn[i].opt) - OPTLEN];
413             }
414             wbuf = wrap_lines(buf, 78, 35, FALSE);
415             fprintf(fp, "%s\n", wbuf);
416             sfree(wbuf);
417         }
418     }
419     fprintf(fp, "\n");
420     fflush(fp);
421 }
422
423 void pr_fopts(FILE *fp, int nf, const t_filenm tfn[], int shell)
424 {
425     int i, j;
426
427     switch (shell)
428     {
429     case eshellCSH:
430         for (i = 0; (i < nf); i++)
431         {
432             fprintf(fp, " \"n/%s/f:*.", tfn[i].opt);
433             if (deffile[tfn[i].ftp].ntps)
434             {
435                 fprintf(fp, "{");
436                 for (j = 0; j < deffile[tfn[i].ftp].ntps; j++)
437                 {
438                     if (j > 0)
439                         fprintf(fp, ",");
440                     fprintf(fp, "%s", deffile[deffile[tfn[i].ftp].tps[j]].ext
441                             + 1);
442                 }
443                 fprintf(fp, "}");
444             }
445             else
446                 fprintf(fp, "%s", deffile[tfn[i].ftp].ext + 1);
447             fprintf(fp, "{");
448             for (j = 0; j < NZEXT; j++)
449                 fprintf(fp, ",%s", z_ext[j]);
450             fprintf(fp, "}/\"");
451         }
452         break;
453     case eshellBASH:
454         for (i = 0; (i < nf); i++)
455         {
456             fprintf(fp, "%s) COMPREPLY=( $(compgen -X '!*.", tfn[i].opt);
457             if (deffile[tfn[i].ftp].ntps)
458             {
459                 fprintf(fp, "+(");
460                 for (j = 0; j < deffile[tfn[i].ftp].ntps; j++)
461                 {
462                     if (j > 0)
463                         fprintf(fp, "|");
464                     fprintf(fp, "%s", deffile[deffile[tfn[i].ftp].tps[j]].ext
465                             + 1);
466                 }
467                 fprintf(fp, ")");
468             }
469             else
470                 fprintf(fp, "%s", deffile[tfn[i].ftp].ext + 1);
471             fprintf(fp, "*(");
472             for (j = 0; j < NZEXT; j++)
473             {
474                 if (j > 0)
475                     fprintf(fp, "|");
476                 fprintf(fp, "%s", z_ext[j]);
477             }
478             fprintf(fp, ")' -f $c ; compgen -S '/' -X '.*' -d $c ));;\n");
479         }
480         break;
481     case eshellZSH:
482         for (i = 0; (i < nf); i++)
483         {
484             fprintf(fp, "- 'c[-1,%s]' -g '*.", tfn[i].opt);
485             if (deffile[tfn[i].ftp].ntps)
486             {
487                 fprintf(fp, "(");
488                 for (j = 0; j < deffile[tfn[i].ftp].ntps; j++)
489                 {
490                     if (j > 0)
491                         fprintf(fp, "|");
492                     fprintf(fp, "%s", deffile[deffile[tfn[i].ftp].tps[j]].ext
493                             + 1);
494                 }
495                 fprintf(fp, ")");
496             }
497             else
498                 fprintf(fp, "%s", deffile[tfn[i].ftp].ext + 1);
499             fprintf(fp, "(");
500             for (j = 0; j < NZEXT; j++)
501                 fprintf(fp, "|%s", z_ext[j]);
502             fprintf(fp, ") *(/)' ");
503         }
504         break;
505     }
506 }
507
508 static void check_opts(int nf, t_filenm fnm[])
509 {
510     int i;
511     const t_deffile *df;
512
513     for (i = 0; (i < nf); i++)
514     {
515         df = &(deffile[fnm[i].ftp]);
516         if (fnm[i].opt == NULL)
517         {
518             if (df->defopt == NULL)
519             {
520                 gmx_fatal(FARGS, "No default cmd-line option for %s (type %d)\n",
521                           deffile[fnm[i].ftp].ext,fnm[i].ftp);
522             }
523             else
524             {
525                 fnm[i].opt=df->defopt;
526             }
527         }
528     }
529 }
530
531 int fn2ftp(const char *fn)
532 {
533     int i, len;
534     const char *feptr;
535     const char *eptr;
536
537     if (!fn)
538         return efNR;
539
540     len = strlen(fn);
541     if ((len >= 4) && (fn[len - 4] == '.'))
542         feptr = &(fn[len - 4]);
543     else
544         return efNR;
545
546     for (i = 0; (i < efNR); i++)
547         if ((eptr = deffile[i].ext) != NULL)
548             if (gmx_strcasecmp(feptr, eptr) == 0)
549                 break;
550
551     return i;
552 }
553
554 static void set_extension(char *buf, int ftp)
555 {
556     int len, extlen;
557     const t_deffile *df;
558
559     /* check if extension is already at end of filename */
560     df = &(deffile[ftp]);
561     len = strlen(buf);
562     extlen = strlen(df->ext);
563     if ((len <= extlen) || (gmx_strcasecmp(&(buf[len - extlen]), df->ext) != 0))
564         strcat(buf, df->ext);
565 }
566
567 static void add_filenm(t_filenm *fnm, const char *filenm)
568 {
569     srenew(fnm->fns, fnm->nfiles+1);
570     fnm->fns[fnm->nfiles] = strdup(filenm);
571     fnm->nfiles++;
572 }
573
574 static void set_grpfnm(t_filenm *fnm, const char *name, gmx_bool bCanNotOverride)
575 {
576     char buf[256], buf2[256];
577     int i, type;
578     gmx_bool bValidExt;
579     int nopts;
580     const int *ftps;
581
582     nopts = deffile[fnm->ftp].ntps;
583     ftps = deffile[fnm->ftp].tps;
584     if ((nopts == 0) || (ftps == NULL))
585         gmx_fatal(FARGS, "nopts == 0 || ftps == NULL");
586
587     bValidExt = FALSE;
588     if (name && (bCanNotOverride || (default_file_name == NULL)))
589     {
590         strcpy(buf,name);
591         /* First check whether we have a valid filename already */
592         type = fn2ftp(name);
593         if ((fnm->flag & ffREAD) && (fnm->ftp == efTRX))
594         {
595             /*if file exist don't add an extension for trajectory reading*/
596             bValidExt = gmx_fexist(name); 
597         }
598         for(i=0; (i<nopts) && !bValidExt; i++)
599         {
600             if (type == ftps[i])
601             {
602                 bValidExt = TRUE;
603             }
604         }
605     }
606     else
607         /* No name given, set the default name */
608         strcpy(buf,ftp2defnm(fnm->ftp));
609
610     if (!bValidExt && (fnm->flag & ffREAD))
611     {
612         /* for input-files only: search for filenames in the directory */
613         for(i=0; (i<nopts) && !bValidExt; i++)
614         {
615             type = ftps[i];
616             strcpy(buf2,buf);
617             set_extension(buf2,type);
618             if (gmx_fexist(buf2))
619             {
620                 bValidExt = TRUE;
621                 strcpy(buf,buf2);
622             }
623         }
624     }
625
626     if (!bValidExt)
627     {
628         /* Use the first extension type */
629         set_extension(buf,ftps[0]);
630     }
631
632     add_filenm(fnm, buf);
633 }
634
635 static void set_filenm(t_filenm *fnm, const char *name, gmx_bool bCanNotOverride,
636                        gmx_bool bReadNode)
637 {
638     /* Set the default filename, extension and option for those fields that 
639      * are not already set. An extension is added if not present, if fn = NULL
640      * or empty, the default filename is given.
641      */
642     char buf[256];
643     int i, len, extlen;
644
645     if ((fnm->flag & ffREAD) && !bReadNode)
646     {
647         return;
648     }
649
650     if ((fnm->ftp < 0) || (fnm->ftp >= efNR))
651         gmx_fatal(FARGS, "file type out of range (%d)",fnm->ftp);
652
653     if (name)
654         strcpy(buf, name);
655     if ((fnm->flag & ffREAD) && name && gmx_fexist(name))
656     {
657         /* check if filename ends in .gz or .Z, if so remove that: */
658         len = strlen(name);
659         for (i=0; i<NZEXT; i++)
660         {
661             extlen = strlen(z_ext[i]);
662             if (len > extlen)
663             {
664                 if (gmx_strcasecmp(name+len-extlen,z_ext[i]) == 0)
665                 {
666                     buf[len-extlen]='\0';
667                     break;
668                 }
669             }
670         }
671     }
672
673     if (deffile[fnm->ftp].ntps)
674     {
675         set_grpfnm(fnm,name ? buf : NULL,bCanNotOverride);
676     }
677     else
678     {
679         if ((name == NULL) || !(bCanNotOverride || (default_file_name ==NULL)))
680         {
681             const char *defnm=ftp2defnm(fnm->ftp);
682             strcpy(buf,defnm);
683         }
684         set_extension(buf,fnm->ftp);
685         
686         add_filenm(fnm, buf);
687     }
688 }
689
690 static void set_filenms(int nf, t_filenm fnm[], gmx_bool bReadNode)
691 {
692     int i;
693
694     for (i = 0; (i < nf); i++)
695         if (!IS_SET(fnm[i]))
696             set_filenm(&(fnm[i]), fnm[i].fn, FALSE, bReadNode);
697 }
698
699 void parse_file_args(int *argc, char *argv[], int nf, t_filenm fnm[],
700                      gmx_bool bKeep, gmx_bool bReadNode)
701 {
702     int i, j;
703     gmx_bool *bRemove;
704
705     check_opts(nf, fnm);
706
707     for (i = 0; (i < nf); i++)
708         UN_SET(fnm[i]);
709
710     if (*argc > 1)
711     {
712         snew(bRemove,(*argc)+1);
713         i = 1;
714         do
715         {
716             for (j = 0; (j < nf); j++)
717             {
718                 if (strcmp(argv[i], fnm[j].opt) == 0)
719                 {
720                     DO_SET(fnm[j]);
721                     bRemove[i] = TRUE;
722                     i++;
723                     /* check if we are out of arguments for this option */
724                     if ((i >= *argc) || (argv[i][0] == '-'))
725                         set_filenm(&fnm[j], fnm[j].fn, FALSE, bReadNode);
726                     /* sweep up all file arguments for this option */
727                     while ((i < *argc) && (argv[i][0] != '-'))
728                     {
729                         set_filenm(&fnm[j], argv[i], TRUE, bReadNode);
730                         bRemove[i] = TRUE;
731                         i++;
732                         /* only repeat for 'multiple' file options: */
733                         if (!IS_MULT(fnm[j]))
734                             break;
735                     }
736
737                     break; /* jump out of 'j' loop */
738                 }
739             }
740             /* No file found corresponding to option argv[i] */
741             if (j == nf)
742                 i++;
743         } while (i < *argc);
744
745         if (!bKeep)
746         {
747             /* Remove used entries */
748             for (i = j = 0; (i <= *argc); i++)
749             {
750                 if (!bRemove[i])
751                     argv[j++] = argv[i];
752             }
753             (*argc) = j - 1;
754         }
755         sfree(bRemove);
756     }
757
758     set_filenms(nf, fnm, bReadNode);
759
760 }
761
762 const char *opt2fn(const char *opt, int nfile, const t_filenm fnm[])
763 {
764     int i;
765
766     for (i = 0; (i < nfile); i++)
767         if (strcmp(opt, fnm[i].opt) == 0)
768         {
769             return fnm[i].fns[0];
770         }
771
772     fprintf(stderr, "No option %s\n", opt);
773
774     return NULL;
775 }
776
777 const char *opt2fn_master(const char *opt, int nfile, const t_filenm fnm[],
778                           t_commrec *cr)
779 {
780     return SIMMASTER(cr) ? opt2fn(opt, nfile, fnm) : NULL;
781 }
782
783 int opt2fns(char **fns[], const char *opt, int nfile, const t_filenm fnm[])
784 {
785     int i;
786
787     for (i = 0; (i < nfile); i++)
788         if (strcmp(opt, fnm[i].opt) == 0)
789         {
790             *fns = fnm[i].fns;
791             return fnm[i].nfiles;
792         }
793
794     fprintf(stderr, "No option %s\n", opt);
795     return 0;
796 }
797
798 const char *ftp2fn(int ftp, int nfile, const t_filenm fnm[])
799 {
800     int i;
801
802     for (i = 0; (i < nfile); i++)
803         if (ftp == fnm[i].ftp)
804             return fnm[i].fns[0];
805
806     fprintf(stderr, "ftp2fn: No filetype %s\n", deffile[ftp].ext);
807     return NULL;
808 }
809
810 int ftp2fns(char **fns[], int ftp, int nfile, const t_filenm fnm[])
811 {
812     int i;
813
814     for (i = 0; (i < nfile); i++)
815         if (ftp == fnm[i].ftp)
816         {
817             *fns = fnm[i].fns;
818             return fnm[i].nfiles;
819         }
820
821     fprintf(stderr, "ftp2fn: No filetype %s\n", deffile[ftp].ext);
822     return 0;
823 }
824
825 gmx_bool ftp2bSet(int ftp, int nfile, const t_filenm fnm[])
826 {
827     int i;
828
829     for (i = 0; (i < nfile); i++)
830         if (ftp == fnm[i].ftp)
831             return (gmx_bool) IS_SET(fnm[i]);
832
833     fprintf(stderr, "ftp2bSet: No filetype %s\n", deffile[ftp].ext);
834
835     return FALSE;
836 }
837
838 gmx_bool opt2bSet(const char *opt, int nfile, const t_filenm fnm[])
839 {
840     int i;
841
842     for (i = 0; (i < nfile); i++)
843         if (strcmp(opt, fnm[i].opt) == 0)
844             return (gmx_bool) IS_SET(fnm[i]);
845
846     fprintf(stderr, "No option %s\n", opt);
847
848     return FALSE;
849 }
850
851 const char *opt2fn_null(const char *opt, int nfile, const t_filenm fnm[])
852 {
853     int i;
854
855     for (i = 0; (i < nfile); i++)
856         if (strcmp(opt, fnm[i].opt) == 0)
857         {
858             if (IS_OPT(fnm[i]) && !IS_SET(fnm[i]))
859                 return NULL;
860             else
861                 return fnm[i].fns[0];
862         }
863     fprintf(stderr, "No option %s\n", opt);
864     return NULL;
865 }
866
867 const char *ftp2fn_null(int ftp, int nfile, const t_filenm fnm[])
868 {
869     int i;
870
871     for (i = 0; (i < nfile); i++)
872         if (ftp == fnm[i].ftp)
873         {
874             if (IS_OPT(fnm[i]) && !IS_SET(fnm[i]))
875                 return NULL;
876             else
877                 return fnm[i].fns[0];
878         }
879     fprintf(stderr, "ftp2fn: No filetype %s\n", deffile[ftp].ext);
880     return NULL;
881 }
882
883 #if 0
884 static void add_filters(char *filter,int *n,int nf,const int ftp[])
885 {
886     char buf[8];
887     int i;
888
889     sprintf(filter,"*.{");
890     for(i=0; (i<nf); i++)
891     {
892         sprintf(buf,"%s",ftp2ext(ftp[i]));
893         if (*n > 0)
894             strcat(filter,",");
895         strcat(filter,buf);
896         (*n) ++;
897     }
898     strcat(filter,"}");
899 }
900
901 char *ftp2filter(int ftp)
902 {
903     int n;
904     static char filter[128];
905
906     filter[0] = '\0';
907     n = 0;
908     switch (ftp)
909     {
910     case efTRX:
911         add_filters(filter,&n,NTRXS,trxs);
912         break;
913     case efTRN:
914         add_filters(filter,&n,NTRNS,trns);
915         break;
916     case efSTO:
917         add_filters(filter,&n,NSTOS,stos);
918         break;
919     case efSTX:
920         add_filters(filter,&n,NSTXS,stxs);
921         break;
922     case efTPX:
923         add_filters(filter,&n,NTPXS,tpxs);
924         break;
925     default:
926         sprintf(filter,"*%s",ftp2ext(ftp));
927         break;
928     }
929     return filter;
930 }
931 #endif
932
933 gmx_bool is_optional(const t_filenm *fnm)
934 {
935     return ((fnm->flag & ffOPT) == ffOPT);
936 }
937
938 gmx_bool is_output(const t_filenm *fnm)
939 {
940     return ((fnm->flag & ffWRITE) == ffWRITE);
941 }
942
943 gmx_bool is_set(const t_filenm *fnm)
944 {
945     return ((fnm->flag & ffSET) == ffSET);
946 }
947
948 int add_suffix_to_output_names(t_filenm *fnm, int nfile, const char *suffix)
949 {
950     int i, j, pos;
951     char buf[STRLEN], newname[STRLEN];
952     char *extpos;
953
954     for (i = 0; i < nfile; i++)
955     {
956         if (is_output(&fnm[i]) && fnm[i].ftp != efCPT)
957         {
958             /* We never use multiple _outputs_, but we might as well check 
959              for it, just in case... */
960             for (j = 0; j < fnm[i].nfiles; j++)
961             {
962                 strncpy(buf, fnm[i].fns[j], STRLEN - 1);
963                 extpos = strrchr(buf, '.');
964                 *extpos = '\0';
965                 sprintf(newname, "%s%s.%s", buf, suffix, extpos + 1);
966                 free(fnm[i].fns[j]);
967                 fnm[i].fns[j] = strdup(newname);
968             }
969         }
970     }
971     return 0;
972 }
973
974 t_filenm *dup_tfn(int nf, const t_filenm tfn[])
975 {
976     int i, j;
977     t_filenm *ret;
978
979     snew(ret, nf);
980     for (i = 0; i < nf; i++)
981     {
982         ret[i] = tfn[i]; /* just directly copy all non-string fields */
983         if (tfn[i].opt)
984             ret[i].opt = strdup(tfn[i].opt);
985         else
986             ret[i].opt = NULL;
987
988         if (tfn[i].fn)
989             ret[i].fn = strdup(tfn[i].fn);
990         else
991             ret[i].fn = NULL;
992
993         if (tfn[i].nfiles > 0)
994         {
995             snew(ret[i].fns,tfn[i].nfiles);
996             for (j = 0; j < tfn[i].nfiles; j++)
997             {
998                 ret[i].fns[j] = strdup(tfn[i].fns[j]);
999             }
1000         }
1001     }
1002     return ret;
1003 }
1004
1005 void done_filenms(int nf, t_filenm fnm[])
1006 {
1007     int i, j;
1008
1009     for (i = 0; i < nf; ++i)
1010     {
1011         for (j = 0; j < fnm[i].nfiles; ++j)
1012         {
1013             sfree(fnm[i].fns[j]);
1014         }
1015         sfree(fnm[i].fns);
1016         fnm[i].fns = NULL;
1017     }
1018 }