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