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