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