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