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