08166cf8813ce820081d6b95a71597b7044e4720
[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, ".edo", "sam",    NULL, "ED sampling output"},
201     { eftASC, ".hat", "gk", NULL, "Fourier transform of spread function" },
202     { eftASC, ".cub", "pot",  NULL, "Gaussian cube file" },
203     { eftASC, ".xpm", "root", NULL, "X PixMap compatible matrix file" },
204     { eftASC, "", "rundir", NULL, "Run directory" } 
205 };
206
207 static char *default_file_name = NULL;
208
209 #ifdef GMX_THREAD_MPI
210 static tMPI_Thread_mutex_t filenm_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
211 #endif
212
213 #define NZEXT 2
214 const char *z_ext[NZEXT] =
215     { ".gz", ".Z" };
216
217 void set_default_file_name(const char *name)
218 {
219     int i;
220 #ifdef GMX_THREAD_MPI
221     tMPI_Thread_mutex_lock(&filenm_mutex);
222 #endif
223     default_file_name = strdup(name);
224 #ifdef GMX_THREAD_MPI
225     tMPI_Thread_mutex_unlock(&filenm_mutex);
226 #endif
227
228 #if 0
229     for(i=0; i<efNR; i++)
230     deffile[i].defnm = default_file_name;
231 #endif
232 }
233
234 const char *ftp2ext(int ftp)
235 {
236     if ((0 <= ftp) && (ftp < efNR))
237         return deffile[ftp].ext + 1;
238     else
239         return "unknown";
240 }
241
242 const char *ftp2ext_generic(int ftp)
243 {
244     if ((0 <= ftp) && (ftp < efNR))
245     {
246         switch (ftp)
247         {
248         case efTRX:
249             return "trx";
250         case efTRN:
251             return "trn";
252         case efSTO:
253             return "sto";
254         case efSTX:
255             return "stx";
256         case efTPX:
257             return "tpx";
258         case efTPS:
259             return "tps";
260         default:
261             return ftp2ext(ftp);
262         }
263     }
264     else
265         return "unknown";
266 }
267
268 const char *ftp2desc(int ftp)
269 {
270     if ((0 <= ftp) && (ftp < efNR))
271         return deffile[ftp].descr;
272     else
273         return "unknown filetype";
274 }
275
276 const char *ftp2ftype(int ftp)
277 {
278     if ((ftp >= 0) && (ftp < efNR))
279     {
280         switch (deffile[ftp].ftype)
281         {
282         case eftASC:
283             return "ASCII";
284         case eftBIN:
285             return "Binary";
286         case eftXDR:
287             return "XDR portable";
288         case eftGEN:
289             return "";
290         default:
291             gmx_fatal(FARGS, "Unknown filetype %d in ftp2ftype",deffile[ftp].ftype);
292             break;
293         }
294     }
295     return "unknown";
296 }
297
298 const char *ftp2defnm(int ftp)
299 {
300     const char *buf = NULL;
301
302 #ifdef GMX_THREAD_MPI
303     tMPI_Thread_mutex_lock(&filenm_mutex);
304 #endif
305
306     if (default_file_name)
307     {
308         buf = default_file_name;
309     }
310     else
311     {
312         if ((0 <= ftp) && (ftp < efNR))
313         {
314             buf = deffile[ftp].defnm;
315         }
316     }
317 #ifdef GMX_THREAD_MPI
318     tMPI_Thread_mutex_unlock(&filenm_mutex);
319 #endif
320
321     return buf;
322 }
323
324 void pr_def(FILE *fp, int ftp)
325 {
326     const t_deffile *df;
327     const char *s = NULL;
328     char *flst, *tmp, *desc;
329     const char *ext;
330     const char *defnm;
331
332     df = &(deffile[ftp]);
333     defnm = ftp2defnm(ftp);
334     /* find default file extension and \tt-ify description */
335     /* FIXME: The constness should not be cast away */
336     flst = (char *) "";
337     desc = strdup(df->descr);
338
339     if (df->ntps)
340     {
341         ext = deffile[df->tps[0]].ext;
342         tmp = strstr(desc, ": ") + 1;
343         if (tmp)
344         {
345             tmp[0] = '\0';
346             tmp++;
347             snew(flst,strlen(tmp)+6);
348             strcpy(flst, " \\tt ");
349             strcat(flst, tmp);
350         }
351     }
352     else
353     {
354         ext = df->ext;
355     }
356     /* now skip dot */
357     if (ext[0])
358         ext++;
359     else
360         ext = "";
361     /* set file contents type */
362     switch (df->ftype)
363     {
364     case eftASC:
365         s = "Asc";
366         break;
367     case eftBIN:
368         s = "Bin";
369         break;
370     case eftXDR:
371         s = "xdr";
372         break;
373     case eftGEN:
374         s = "";
375         break;
376     default:
377         gmx_fatal(FARGS, "Unimplemented filetype %d %d",ftp,
378         df->ftype);
379     }
380     fprintf(fp,"\\tt %8s & \\tt %3s & %3s & \\tt %2s & %s%s \\\\[-0.1ex]\n",
381         defnm, ext, s, df->defopt ? df->defopt : "",
382         check_tex(desc),check_tex(flst));
383     free(desc);
384 }
385
386 void pr_fns(FILE *fp, int nf, const t_filenm tfn[])
387 {
388     int i, f;
389     size_t j;
390     char buf[256], *wbuf, opt_buf[32];
391 #define OPTLEN 4
392 #define NAMELEN 14
393     fprintf(fp, "%6s %12s  %-12s %s\n", "Option", "Filename", "Type",
394             "Description");
395     fprintf(fp,
396             "------------------------------------------------------------\n");
397     for (i = 0; (i < nf); i++)
398     {
399         for (f = 0; (f < tfn[i].nfiles); f++)
400         {
401             sprintf(buf, "%4s %14s  %-12s ", (f == 0) ? tfn[i].opt : "",
402                     tfn[i].fns[f], (f == 0) ? fileopt(tfn[i].flag, opt_buf, 32)
403                         : "");
404             if (f < tfn[i].nfiles - 1)
405                 fprintf(fp, "%s\n", buf);
406         }
407         if (tfn[i].nfiles > 0)
408         {
409             strcat(buf, deffile[tfn[i].ftp].descr);
410             if ((strlen(tfn[i].opt) > OPTLEN)
411                 && (strlen(tfn[i].opt) <= ((OPTLEN + NAMELEN)
412                     - strlen(tfn[i].fns[tfn[i].nfiles - 1]))))
413             {
414                 for (j = strlen(tfn[i].opt); j < strlen(buf)
415                     - (strlen(tfn[i].opt) - OPTLEN) + 1; j++)
416                     buf[j] = buf[j + strlen(tfn[i].opt) - OPTLEN];
417             }
418             wbuf = wrap_lines(buf, 78, 35, FALSE);
419             fprintf(fp, "%s\n", wbuf);
420             sfree(wbuf);
421         }
422     }
423     fprintf(fp, "\n");
424     fflush(fp);
425 }
426
427 void pr_fopts(FILE *fp, int nf, const t_filenm tfn[], int shell)
428 {
429     int i, j;
430
431     switch (shell)
432     {
433     case eshellCSH:
434         for (i = 0; (i < nf); i++)
435         {
436             fprintf(fp, " \"n/%s/f:*.", tfn[i].opt);
437             if (deffile[tfn[i].ftp].ntps)
438             {
439                 fprintf(fp, "{");
440                 for (j = 0; j < deffile[tfn[i].ftp].ntps; j++)
441                 {
442                     if (j > 0)
443                         fprintf(fp, ",");
444                     fprintf(fp, "%s", deffile[deffile[tfn[i].ftp].tps[j]].ext
445                             + 1);
446                 }
447                 fprintf(fp, "}");
448             }
449             else
450                 fprintf(fp, "%s", deffile[tfn[i].ftp].ext + 1);
451             fprintf(fp, "{");
452             for (j = 0; j < NZEXT; j++)
453                 fprintf(fp, ",%s", z_ext[j]);
454             fprintf(fp, "}/\"");
455         }
456         break;
457     case eshellBASH:
458         for (i = 0; (i < nf); i++)
459         {
460             fprintf(fp, "%s) COMPREPLY=( $(compgen -X '!*.", tfn[i].opt);
461             if (deffile[tfn[i].ftp].ntps)
462             {
463                 fprintf(fp, "+(");
464                 for (j = 0; j < deffile[tfn[i].ftp].ntps; j++)
465                 {
466                     if (j > 0)
467                         fprintf(fp, "|");
468                     fprintf(fp, "%s", deffile[deffile[tfn[i].ftp].tps[j]].ext
469                             + 1);
470                 }
471                 fprintf(fp, ")");
472             }
473             else
474                 fprintf(fp, "%s", deffile[tfn[i].ftp].ext + 1);
475             fprintf(fp, "*(");
476             for (j = 0; j < NZEXT; j++)
477             {
478                 if (j > 0)
479                     fprintf(fp, "|");
480                 fprintf(fp, "%s", z_ext[j]);
481             }
482             fprintf(fp, ")' -f $c ; compgen -S '/' -X '.*' -d $c ));;\n");
483         }
484         break;
485     case eshellZSH:
486         for (i = 0; (i < nf); i++)
487         {
488             fprintf(fp, "- 'c[-1,%s]' -g '*.", tfn[i].opt);
489             if (deffile[tfn[i].ftp].ntps)
490             {
491                 fprintf(fp, "(");
492                 for (j = 0; j < deffile[tfn[i].ftp].ntps; j++)
493                 {
494                     if (j > 0)
495                         fprintf(fp, "|");
496                     fprintf(fp, "%s", deffile[deffile[tfn[i].ftp].tps[j]].ext
497                             + 1);
498                 }
499                 fprintf(fp, ")");
500             }
501             else
502                 fprintf(fp, "%s", deffile[tfn[i].ftp].ext + 1);
503             fprintf(fp, "(");
504             for (j = 0; j < NZEXT; j++)
505                 fprintf(fp, "|%s", z_ext[j]);
506             fprintf(fp, ") *(/)' ");
507         }
508         break;
509     }
510 }
511
512 static void check_opts(int nf, t_filenm fnm[])
513 {
514     int i;
515     const t_deffile *df;
516
517     for (i = 0; (i < nf); i++)
518     {
519         df = &(deffile[fnm[i].ftp]);
520         if (fnm[i].opt == NULL)
521         {
522             if (df->defopt == NULL)
523             {
524                 gmx_fatal(FARGS, "No default cmd-line option for %s (type %d)\n",
525                           deffile[fnm[i].ftp].ext,fnm[i].ftp);
526             }
527             else
528             {
529                 fnm[i].opt=df->defopt;
530             }
531         }
532     }
533 }
534
535 int fn2ftp(const char *fn)
536 {
537     int i, len;
538     const char *feptr;
539     const char *eptr;
540
541     if (!fn)
542         return efNR;
543
544     len = strlen(fn);
545     if ((len >= 4) && (fn[len - 4] == '.'))
546         feptr = &(fn[len - 4]);
547     else
548         return efNR;
549
550     for (i = 0; (i < efNR); i++)
551         if ((eptr = deffile[i].ext) != NULL)
552             if (gmx_strcasecmp(feptr, eptr) == 0)
553                 break;
554
555     return i;
556 }
557
558 static void set_extension(char *buf, int ftp)
559 {
560     int len, extlen;
561     const t_deffile *df;
562
563     /* check if extension is already at end of filename */
564     df = &(deffile[ftp]);
565     len = strlen(buf);
566     extlen = strlen(df->ext);
567     if ((len <= extlen) || (gmx_strcasecmp(&(buf[len - extlen]), df->ext) != 0))
568         strcat(buf, df->ext);
569 }
570
571 static void add_filenm(t_filenm *fnm, const char *filenm)
572 {
573     srenew(fnm->fns, fnm->nfiles+1);
574     fnm->fns[fnm->nfiles] = strdup(filenm);
575     fnm->nfiles++;
576 }
577
578 static void set_grpfnm(t_filenm *fnm, const char *name, gmx_bool bCanNotOverride)
579 {
580     char buf[256], buf2[256];
581     int i, type;
582     gmx_bool bValidExt;
583     int nopts;
584     const int *ftps;
585
586     nopts = deffile[fnm->ftp].ntps;
587     ftps = deffile[fnm->ftp].tps;
588     if ((nopts == 0) || (ftps == NULL))
589         gmx_fatal(FARGS, "nopts == 0 || ftps == NULL");
590
591     bValidExt = FALSE;
592     if (name && (bCanNotOverride || (default_file_name == NULL)))
593     {
594         strcpy(buf,name);
595         /* First check whether we have a valid filename already */
596         type = fn2ftp(name);
597         if ((fnm->flag & ffREAD) && (fnm->ftp == efTRX))
598         {
599             /*if file exist don't add an extension for trajectory reading*/
600             bValidExt = gmx_fexist(name); 
601         }
602         for(i=0; (i<nopts) && !bValidExt; i++)
603         {
604             if (type == ftps[i])
605             {
606                 bValidExt = TRUE;
607             }
608         }
609     }
610     else
611         /* No name given, set the default name */
612         strcpy(buf,ftp2defnm(fnm->ftp));
613
614     if (!bValidExt && (fnm->flag & ffREAD))
615     {
616         /* for input-files only: search for filenames in the directory */
617         for(i=0; (i<nopts) && !bValidExt; i++)
618         {
619             type = ftps[i];
620             strcpy(buf2,buf);
621             set_extension(buf2,type);
622             if (gmx_fexist(buf2))
623             {
624                 bValidExt = TRUE;
625                 strcpy(buf,buf2);
626             }
627         }
628     }
629
630     if (!bValidExt)
631     {
632         /* Use the first extension type */
633         set_extension(buf,ftps[0]);
634     }
635
636     add_filenm(fnm, buf);
637 }
638
639 static void set_filenm(t_filenm *fnm, const char *name, gmx_bool bCanNotOverride,
640                        gmx_bool bReadNode)
641 {
642     /* Set the default filename, extension and option for those fields that 
643      * are not already set. An extension is added if not present, if fn = NULL
644      * or empty, the default filename is given.
645      */
646     char buf[256];
647     int i, len, extlen;
648
649     if ((fnm->flag & ffREAD) && !bReadNode)
650     {
651         return;
652     }
653
654     if ((fnm->ftp < 0) || (fnm->ftp >= efNR))
655         gmx_fatal(FARGS, "file type out of range (%d)",fnm->ftp);
656
657     if (name)
658         strcpy(buf, name);
659     if ((fnm->flag & ffREAD) && name && gmx_fexist(name))
660     {
661         /* check if filename ends in .gz or .Z, if so remove that: */
662         len = strlen(name);
663         for (i=0; i<NZEXT; i++)
664         {
665             extlen = strlen(z_ext[i]);
666             if (len > extlen)
667             {
668                 if (gmx_strcasecmp(name+len-extlen,z_ext[i]) == 0)
669                 {
670                     buf[len-extlen]='\0';
671                     break;
672                 }
673             }
674         }
675     }
676
677     if (deffile[fnm->ftp].ntps)
678     {
679         set_grpfnm(fnm,name ? buf : NULL,bCanNotOverride);
680     }
681     else
682     {
683         if ((name == NULL) || !(bCanNotOverride || (default_file_name ==NULL)))
684         {
685             const char *defnm=ftp2defnm(fnm->ftp);
686             strcpy(buf,defnm);
687         }
688         set_extension(buf,fnm->ftp);
689         
690         add_filenm(fnm, buf);
691     }
692 }
693
694 static void set_filenms(int nf, t_filenm fnm[], gmx_bool bReadNode)
695 {
696     int i;
697
698     for (i = 0; (i < nf); i++)
699         if (!IS_SET(fnm[i]))
700             set_filenm(&(fnm[i]), fnm[i].fn, FALSE, bReadNode);
701 }
702
703 void parse_file_args(int *argc, char *argv[], int nf, t_filenm fnm[],
704                      gmx_bool bKeep, gmx_bool bReadNode)
705 {
706     int i, j;
707     gmx_bool *bRemove;
708
709     check_opts(nf, fnm);
710
711     for (i = 0; (i < nf); i++)
712         UN_SET(fnm[i]);
713
714     if (*argc > 1)
715     {
716         snew(bRemove,(*argc)+1);
717         i = 1;
718         do
719         {
720             for (j = 0; (j < nf); j++)
721             {
722                 if (strcmp(argv[i], fnm[j].opt) == 0)
723                 {
724                     DO_SET(fnm[j]);
725                     bRemove[i] = TRUE;
726                     i++;
727                     /* check if we are out of arguments for this option */
728                     if ((i >= *argc) || (argv[i][0] == '-'))
729                         set_filenm(&fnm[j], fnm[j].fn, FALSE, bReadNode);
730                     /* sweep up all file arguments for this option */
731                     while ((i < *argc) && (argv[i][0] != '-'))
732                     {
733                         set_filenm(&fnm[j], argv[i], TRUE, bReadNode);
734                         bRemove[i] = TRUE;
735                         i++;
736                         /* only repeat for 'multiple' file options: */
737                         if (!IS_MULT(fnm[j]))
738                             break;
739                     }
740
741                     break; /* jump out of 'j' loop */
742                 }
743             }
744             /* No file found corresponding to option argv[i] */
745             if (j == nf)
746                 i++;
747         } while (i < *argc);
748
749         if (!bKeep)
750         {
751             /* Remove used entries */
752             for (i = j = 0; (i <= *argc); i++)
753             {
754                 if (!bRemove[i])
755                     argv[j++] = argv[i];
756             }
757             (*argc) = j - 1;
758         }
759         sfree(bRemove);
760     }
761
762     set_filenms(nf, fnm, bReadNode);
763
764 }
765
766 const char *opt2fn(const char *opt, int nfile, const t_filenm fnm[])
767 {
768     int i;
769
770     for (i = 0; (i < nfile); i++)
771         if (strcmp(opt, fnm[i].opt) == 0)
772         {
773             return fnm[i].fns[0];
774         }
775
776     fprintf(stderr, "No option %s\n", opt);
777
778     return NULL;
779 }
780
781 const char *opt2fn_master(const char *opt, int nfile, const t_filenm fnm[],
782                           t_commrec *cr)
783 {
784     return SIMMASTER(cr) ? opt2fn(opt, nfile, fnm) : NULL;
785 }
786
787 int opt2fns(char **fns[], const char *opt, int nfile, const t_filenm fnm[])
788 {
789     int i;
790
791     for (i = 0; (i < nfile); i++)
792         if (strcmp(opt, fnm[i].opt) == 0)
793         {
794             *fns = fnm[i].fns;
795             return fnm[i].nfiles;
796         }
797
798     fprintf(stderr, "No option %s\n", opt);
799     return 0;
800 }
801
802 const char *ftp2fn(int ftp, int nfile, const t_filenm fnm[])
803 {
804     int i;
805
806     for (i = 0; (i < nfile); i++)
807         if (ftp == fnm[i].ftp)
808             return fnm[i].fns[0];
809
810     fprintf(stderr, "ftp2fn: No filetype %s\n", deffile[ftp].ext);
811     return NULL;
812 }
813
814 int ftp2fns(char **fns[], int ftp, int nfile, const t_filenm fnm[])
815 {
816     int i;
817
818     for (i = 0; (i < nfile); i++)
819         if (ftp == fnm[i].ftp)
820         {
821             *fns = fnm[i].fns;
822             return fnm[i].nfiles;
823         }
824
825     fprintf(stderr, "ftp2fn: No filetype %s\n", deffile[ftp].ext);
826     return 0;
827 }
828
829 gmx_bool ftp2bSet(int ftp, int nfile, const t_filenm fnm[])
830 {
831     int i;
832
833     for (i = 0; (i < nfile); i++)
834         if (ftp == fnm[i].ftp)
835             return (gmx_bool) IS_SET(fnm[i]);
836
837     fprintf(stderr, "ftp2bSet: No filetype %s\n", deffile[ftp].ext);
838
839     return FALSE;
840 }
841
842 gmx_bool opt2bSet(const char *opt, int nfile, const t_filenm fnm[])
843 {
844     int i;
845
846     for (i = 0; (i < nfile); i++)
847         if (strcmp(opt, fnm[i].opt) == 0)
848             return (gmx_bool) IS_SET(fnm[i]);
849
850     fprintf(stderr, "No option %s\n", opt);
851
852     return FALSE;
853 }
854
855 const char *opt2fn_null(const char *opt, int nfile, const t_filenm fnm[])
856 {
857     int i;
858
859     for (i = 0; (i < nfile); i++)
860         if (strcmp(opt, fnm[i].opt) == 0)
861         {
862             if (IS_OPT(fnm[i]) && !IS_SET(fnm[i]))
863                 return NULL;
864             else
865                 return fnm[i].fns[0];
866         }
867     fprintf(stderr, "No option %s\n", opt);
868     return NULL;
869 }
870
871 const char *ftp2fn_null(int ftp, int nfile, const t_filenm fnm[])
872 {
873     int i;
874
875     for (i = 0; (i < nfile); i++)
876         if (ftp == fnm[i].ftp)
877         {
878             if (IS_OPT(fnm[i]) && !IS_SET(fnm[i]))
879                 return NULL;
880             else
881                 return fnm[i].fns[0];
882         }
883     fprintf(stderr, "ftp2fn: No filetype %s\n", deffile[ftp].ext);
884     return NULL;
885 }
886
887 #if 0
888 static void add_filters(char *filter,int *n,int nf,const int ftp[])
889 {
890     char buf[8];
891     int i;
892
893     sprintf(filter,"*.{");
894     for(i=0; (i<nf); i++)
895     {
896         sprintf(buf,"%s",ftp2ext(ftp[i]));
897         if (*n > 0)
898             strcat(filter,",");
899         strcat(filter,buf);
900         (*n) ++;
901     }
902     strcat(filter,"}");
903 }
904
905 char *ftp2filter(int ftp)
906 {
907     int n;
908     static char filter[128];
909
910     filter[0] = '\0';
911     n = 0;
912     switch (ftp)
913     {
914     case efTRX:
915         add_filters(filter,&n,NTRXS,trxs);
916         break;
917     case efTRN:
918         add_filters(filter,&n,NTRNS,trns);
919         break;
920     case efSTO:
921         add_filters(filter,&n,NSTOS,stos);
922         break;
923     case efSTX:
924         add_filters(filter,&n,NSTXS,stxs);
925         break;
926     case efTPX:
927         add_filters(filter,&n,NTPXS,tpxs);
928         break;
929     default:
930         sprintf(filter,"*%s",ftp2ext(ftp));
931         break;
932     }
933     return filter;
934 }
935 #endif
936
937 gmx_bool is_optional(const t_filenm *fnm)
938 {
939     return ((fnm->flag & ffOPT) == ffOPT);
940 }
941
942 gmx_bool is_output(const t_filenm *fnm)
943 {
944     return ((fnm->flag & ffWRITE) == ffWRITE);
945 }
946
947 gmx_bool is_set(const t_filenm *fnm)
948 {
949     return ((fnm->flag & ffSET) == ffSET);
950 }
951
952 int add_suffix_to_output_names(t_filenm *fnm, int nfile, const char *suffix)
953 {
954     int i, j, pos;
955     char buf[STRLEN], newname[STRLEN];
956     char *extpos;
957
958     for (i = 0; i < nfile; i++)
959     {
960         if (is_output(&fnm[i]) && fnm[i].ftp != efCPT)
961         {
962             /* We never use multiple _outputs_, but we might as well check 
963              for it, just in case... */
964             for (j = 0; j < fnm[i].nfiles; j++)
965             {
966                 strncpy(buf, fnm[i].fns[j], STRLEN - 1);
967                 extpos = strrchr(buf, '.');
968                 *extpos = '\0';
969                 sprintf(newname, "%s%s.%s", buf, suffix, extpos + 1);
970                 free(fnm[i].fns[j]);
971                 fnm[i].fns[j] = strdup(newname);
972             }
973         }
974     }
975     return 0;
976 }
977
978 t_filenm *dup_tfn(int nf, const t_filenm tfn[])
979 {
980     int i, j;
981     t_filenm *ret;
982
983     snew(ret, nf);
984     for (i = 0; i < nf; i++)
985     {
986         ret[i] = tfn[i]; /* just directly copy all non-string fields */
987         if (tfn[i].opt)
988             ret[i].opt = strdup(tfn[i].opt);
989         else
990             ret[i].opt = NULL;
991
992         if (tfn[i].fn)
993             ret[i].fn = strdup(tfn[i].fn);
994         else
995             ret[i].fn = NULL;
996
997         if (tfn[i].nfiles > 0)
998         {
999             snew(ret[i].fns,tfn[i].nfiles);
1000             for (j = 0; j < tfn[i].nfiles; j++)
1001             {
1002                 ret[i].fns[j] = strdup(tfn[i].fns[j]);
1003             }
1004         }
1005     }
1006     return ret;
1007 }
1008
1009 void done_filenms(int nf, t_filenm fnm[])
1010 {
1011     int i, j;
1012
1013     for (i = 0; i < nf; ++i)
1014     {
1015         for (j = 0; j < fnm[i].nfiles; ++j)
1016         {
1017             sfree(fnm[i].fns[j]);
1018         }
1019         sfree(fnm[i].fns);
1020         fnm[i].fns = NULL;
1021     }
1022 }