3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
30 * For more info, check our website at http://www.gromacs.org
33 * GROningen Mixture of Alchemy and Childrens' Stories
44 #include "gmx_fatal.h"
52 #include "thread_mpi.h"
55 /* NOTE: this was a cesspool of thread-unsafe code, has now been
56 properly proteced by mutexes (hopefully). */
58 /* XDR should be available on all platforms now,
59 * but we keep the possibility of turning it off...
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))
72 eftASC
, eftBIN
, eftXDR
, eftGEN
, eftNR
75 /* To support multiple file types with one general (eg TRX) we have
78 static const int trxs
[] =
83 efTRJ
, efGRO
, efG96
, efPDB
, efG87
};
84 #define NTRXS asize(trxs)
86 static const int tros
[] =
91 efTRJ
, efGRO
, efG96
, efPDB
, efG87
};
92 #define NTROS asize(tros)
94 static const int trns
[] =
100 #define NTRNS asize(trns)
102 static const int stos
[] =
103 { efGRO
, efG96
, efPDB
, efBRK
, efENT
, efESP
, efXYZ
};
104 #define NSTOS asize(stos)
106 static const int stxs
[] =
107 { efGRO
, efG96
, efPDB
, efBRK
, efENT
, efESP
, efXYZ
,
112 #define NSTXS asize(stxs)
114 static const int tpxs
[] =
120 #define NTPXS asize(tpxs)
122 static const int tpss
[] =
127 efTPB
, efTPA
, efGRO
, efG96
, efPDB
, efBRK
, efENT
};
128 #define NTPSS asize(tpss)
141 /* this array should correspond to the enum in include/types/filenm.h */
142 static const t_deffile
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.",
161 { eftGEN
, ".???", "out", "-o", "Structure file: gro g96 pdb etc.",
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",
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" }
203 static char *default_file_name
= NULL
;
206 static tMPI_Thread_mutex_t filenm_mutex
=TMPI_THREAD_MUTEX_INITIALIZER
;
210 const char *z_ext
[NZEXT
] =
213 void set_default_file_name(const char *name
)
217 tMPI_Thread_mutex_lock(&filenm_mutex
);
219 default_file_name
= strdup(name
);
221 tMPI_Thread_mutex_unlock(&filenm_mutex
);
225 for(i
=0; i
<efNR
; i
++)
226 deffile
[i
].defnm
= default_file_name
;
230 const char *ftp2ext(int ftp
)
232 if ((0 <= ftp
) && (ftp
< efNR
))
233 return deffile
[ftp
].ext
+ 1;
238 const char *ftp2ext_generic(int ftp
)
240 if ((0 <= ftp
) && (ftp
< efNR
))
264 const char *ftp2desc(int ftp
)
266 if ((0 <= ftp
) && (ftp
< efNR
))
267 return deffile
[ftp
].descr
;
269 return "unknown filetype";
272 const char *ftp2ftype(int ftp
)
274 if ((ftp
>= 0) && (ftp
< efNR
))
276 switch (deffile
[ftp
].ftype
)
283 return "XDR portable";
287 gmx_fatal(FARGS
, "Unknown filetype %d in ftp2ftype",deffile
[ftp
].ftype
);
294 const char *ftp2defnm(int ftp
)
296 const char *buf
= NULL
;
299 tMPI_Thread_mutex_lock(&filenm_mutex
);
302 if (default_file_name
)
304 buf
= default_file_name
;
308 if ((0 <= ftp
) && (ftp
< efNR
))
310 buf
= deffile
[ftp
].defnm
;
314 tMPI_Thread_mutex_unlock(&filenm_mutex
);
320 void pr_def(FILE *fp
, int ftp
)
323 const char *s
= NULL
;
324 char *flst
, *tmp
, *desc
;
328 df
= &(deffile
[ftp
]);
329 defnm
= ftp2defnm(ftp
);
330 /* find default file extension and \tt-ify description */
331 /* FIXME: The constness should not be cast away */
333 desc
= strdup(df
->descr
);
337 ext
= deffile
[df
->tps
[0]].ext
;
338 tmp
= strstr(desc
, ": ") + 1;
343 snew(flst
,strlen(tmp
)+6);
344 strcpy(flst
, " \\tt ");
357 /* set file contents type */
373 gmx_fatal(FARGS
, "Unimplemented filetype %d %d",ftp
,
376 fprintf(fp
,"\\tt %8s & \\tt %3s & %3s & \\tt %2s & %s%s \\\\[-0.1ex]\n",
377 defnm
, ext
, s
, df
->defopt
? df
->defopt
: "",
378 check_tex(desc
),check_tex(flst
));
382 void pr_fns(FILE *fp
, int nf
, const t_filenm tfn
[])
386 char buf
[256], *wbuf
, opt_buf
[32];
389 fprintf(fp
, "%6s %12s %-12s %s\n", "Option", "Filename", "Type",
392 "------------------------------------------------------------\n");
393 for (i
= 0; (i
< nf
); i
++)
395 for (f
= 0; (f
< tfn
[i
].nfiles
); f
++)
397 sprintf(buf
, "%4s %14s %-12s ", (f
== 0) ? tfn
[i
].opt
: "",
398 tfn
[i
].fns
[f
], (f
== 0) ? fileopt(tfn
[i
].flag
, opt_buf
, 32)
400 if (f
< tfn
[i
].nfiles
- 1)
401 fprintf(fp
, "%s\n", buf
);
403 if (tfn
[i
].nfiles
> 0)
405 strcat(buf
, deffile
[tfn
[i
].ftp
].descr
);
406 if ((strlen(tfn
[i
].opt
) > OPTLEN
)
407 && (strlen(tfn
[i
].opt
) <= ((OPTLEN
+ NAMELEN
)
408 - strlen(tfn
[i
].fns
[tfn
[i
].nfiles
- 1]))))
410 for (j
= strlen(tfn
[i
].opt
); j
< strlen(buf
)
411 - (strlen(tfn
[i
].opt
) - OPTLEN
) + 1; j
++)
412 buf
[j
] = buf
[j
+ strlen(tfn
[i
].opt
) - OPTLEN
];
414 wbuf
= wrap_lines(buf
, 78, 35, FALSE
);
415 fprintf(fp
, "%s\n", wbuf
);
423 void pr_fopts(FILE *fp
, int nf
, const t_filenm tfn
[], int shell
)
430 for (i
= 0; (i
< nf
); i
++)
432 fprintf(fp
, " \"n/%s/f:*.", tfn
[i
].opt
);
433 if (deffile
[tfn
[i
].ftp
].ntps
)
436 for (j
= 0; j
< deffile
[tfn
[i
].ftp
].ntps
; j
++)
440 fprintf(fp
, "%s", deffile
[deffile
[tfn
[i
].ftp
].tps
[j
]].ext
446 fprintf(fp
, "%s", deffile
[tfn
[i
].ftp
].ext
+ 1);
448 for (j
= 0; j
< NZEXT
; j
++)
449 fprintf(fp
, ",%s", z_ext
[j
]);
454 for (i
= 0; (i
< nf
); i
++)
456 fprintf(fp
, "%s) COMPREPLY=( $(compgen -X '!*.", tfn
[i
].opt
);
457 if (deffile
[tfn
[i
].ftp
].ntps
)
460 for (j
= 0; j
< deffile
[tfn
[i
].ftp
].ntps
; j
++)
464 fprintf(fp
, "%s", deffile
[deffile
[tfn
[i
].ftp
].tps
[j
]].ext
470 fprintf(fp
, "%s", deffile
[tfn
[i
].ftp
].ext
+ 1);
472 for (j
= 0; j
< NZEXT
; j
++)
476 fprintf(fp
, "%s", z_ext
[j
]);
478 fprintf(fp
, ")' -f $c ; compgen -S '/' -X '.*' -d $c ));;\n");
482 for (i
= 0; (i
< nf
); i
++)
484 fprintf(fp
, "- 'c[-1,%s]' -g '*.", tfn
[i
].opt
);
485 if (deffile
[tfn
[i
].ftp
].ntps
)
488 for (j
= 0; j
< deffile
[tfn
[i
].ftp
].ntps
; j
++)
492 fprintf(fp
, "%s", deffile
[deffile
[tfn
[i
].ftp
].tps
[j
]].ext
498 fprintf(fp
, "%s", deffile
[tfn
[i
].ftp
].ext
+ 1);
500 for (j
= 0; j
< NZEXT
; j
++)
501 fprintf(fp
, "|%s", z_ext
[j
]);
502 fprintf(fp
, ") *(/)' ");
508 static void check_opts(int nf
, t_filenm fnm
[])
513 for (i
= 0; (i
< nf
); i
++)
515 df
= &(deffile
[fnm
[i
].ftp
]);
516 if (fnm
[i
].opt
== NULL
)
518 if (df
->defopt
== NULL
)
520 gmx_fatal(FARGS
, "No default cmd-line option for %s (type %d)\n",
521 deffile
[fnm
[i
].ftp
].ext
,fnm
[i
].ftp
);
525 fnm
[i
].opt
=df
->defopt
;
531 int fn2ftp(const char *fn
)
541 if ((len
>= 4) && (fn
[len
- 4] == '.'))
542 feptr
= &(fn
[len
- 4]);
546 for (i
= 0; (i
< efNR
); i
++)
547 if ((eptr
= deffile
[i
].ext
) != NULL
)
548 if (gmx_strcasecmp(feptr
, eptr
) == 0)
554 static void set_extension(char *buf
, int ftp
)
559 /* check if extension is already at end of filename */
560 df
= &(deffile
[ftp
]);
562 extlen
= strlen(df
->ext
);
563 if ((len
<= extlen
) || (gmx_strcasecmp(&(buf
[len
- extlen
]), df
->ext
) != 0))
564 strcat(buf
, df
->ext
);
567 static void add_filenm(t_filenm
*fnm
, const char *filenm
)
569 srenew(fnm
->fns
, fnm
->nfiles
+1);
570 fnm
->fns
[fnm
->nfiles
] = strdup(filenm
);
574 static void set_grpfnm(t_filenm
*fnm
, const char *name
, gmx_bool bCanNotOverride
)
576 char buf
[256], buf2
[256];
582 nopts
= deffile
[fnm
->ftp
].ntps
;
583 ftps
= deffile
[fnm
->ftp
].tps
;
584 if ((nopts
== 0) || (ftps
== NULL
))
585 gmx_fatal(FARGS
, "nopts == 0 || ftps == NULL");
588 if (name
&& (bCanNotOverride
|| (default_file_name
== NULL
)))
591 /* First check whether we have a valid filename already */
593 if ((fnm
->flag
& ffREAD
) && (fnm
->ftp
== efTRX
))
595 /*if file exist don't add an extension for trajectory reading*/
596 bValidExt
= gmx_fexist(name
);
598 for(i
=0; (i
<nopts
) && !bValidExt
; i
++)
607 /* No name given, set the default name */
608 strcpy(buf
,ftp2defnm(fnm
->ftp
));
610 if (!bValidExt
&& (fnm
->flag
& ffREAD
))
612 /* for input-files only: search for filenames in the directory */
613 for(i
=0; (i
<nopts
) && !bValidExt
; i
++)
617 set_extension(buf2
,type
);
618 if (gmx_fexist(buf2
))
628 /* Use the first extension type */
629 set_extension(buf
,ftps
[0]);
632 add_filenm(fnm
, buf
);
635 static void set_filenm(t_filenm
*fnm
, const char *name
, gmx_bool bCanNotOverride
,
638 /* Set the default filename, extension and option for those fields that
639 * are not already set. An extension is added if not present, if fn = NULL
640 * or empty, the default filename is given.
645 if ((fnm
->flag
& ffREAD
) && !bReadNode
)
650 if ((fnm
->ftp
< 0) || (fnm
->ftp
>= efNR
))
651 gmx_fatal(FARGS
, "file type out of range (%d)",fnm
->ftp
);
655 if ((fnm
->flag
& ffREAD
) && name
&& gmx_fexist(name
))
657 /* check if filename ends in .gz or .Z, if so remove that: */
659 for (i
=0; i
<NZEXT
; i
++)
661 extlen
= strlen(z_ext
[i
]);
664 if (gmx_strcasecmp(name
+len
-extlen
,z_ext
[i
]) == 0)
666 buf
[len
-extlen
]='\0';
673 if (deffile
[fnm
->ftp
].ntps
)
675 set_grpfnm(fnm
,name
? buf
: NULL
,bCanNotOverride
);
679 if ((name
== NULL
) || !(bCanNotOverride
|| (default_file_name
==NULL
)))
681 const char *defnm
=ftp2defnm(fnm
->ftp
);
684 set_extension(buf
,fnm
->ftp
);
686 add_filenm(fnm
, buf
);
690 static void set_filenms(int nf
, t_filenm fnm
[], gmx_bool bReadNode
)
694 for (i
= 0; (i
< nf
); i
++)
696 set_filenm(&(fnm
[i
]), fnm
[i
].fn
, FALSE
, bReadNode
);
699 void parse_file_args(int *argc
, char *argv
[], int nf
, t_filenm fnm
[],
700 gmx_bool bKeep
, gmx_bool bReadNode
)
707 for (i
= 0; (i
< nf
); i
++)
712 snew(bRemove
,(*argc
)+1);
716 for (j
= 0; (j
< nf
); j
++)
718 if (strcmp(argv
[i
], fnm
[j
].opt
) == 0)
723 /* check if we are out of arguments for this option */
724 if ((i
>= *argc
) || (argv
[i
][0] == '-'))
725 set_filenm(&fnm
[j
], fnm
[j
].fn
, FALSE
, bReadNode
);
726 /* sweep up all file arguments for this option */
727 while ((i
< *argc
) && (argv
[i
][0] != '-'))
729 set_filenm(&fnm
[j
], argv
[i
], TRUE
, bReadNode
);
732 /* only repeat for 'multiple' file options: */
733 if (!IS_MULT(fnm
[j
]))
737 break; /* jump out of 'j' loop */
740 /* No file found corresponding to option argv[i] */
747 /* Remove used entries */
748 for (i
= j
= 0; (i
<= *argc
); i
++)
758 set_filenms(nf
, fnm
, bReadNode
);
762 const char *opt2fn(const char *opt
, int nfile
, const t_filenm fnm
[])
766 for (i
= 0; (i
< nfile
); i
++)
767 if (strcmp(opt
, fnm
[i
].opt
) == 0)
769 return fnm
[i
].fns
[0];
772 fprintf(stderr
, "No option %s\n", opt
);
777 const char *opt2fn_master(const char *opt
, int nfile
, const t_filenm fnm
[],
780 return SIMMASTER(cr
) ? opt2fn(opt
, nfile
, fnm
) : NULL
;
783 int opt2fns(char **fns
[], const char *opt
, int nfile
, const t_filenm fnm
[])
787 for (i
= 0; (i
< nfile
); i
++)
788 if (strcmp(opt
, fnm
[i
].opt
) == 0)
791 return fnm
[i
].nfiles
;
794 fprintf(stderr
, "No option %s\n", opt
);
798 const char *ftp2fn(int ftp
, int nfile
, const t_filenm fnm
[])
802 for (i
= 0; (i
< nfile
); i
++)
803 if (ftp
== fnm
[i
].ftp
)
804 return fnm
[i
].fns
[0];
806 fprintf(stderr
, "ftp2fn: No filetype %s\n", deffile
[ftp
].ext
);
810 int ftp2fns(char **fns
[], int ftp
, int nfile
, const t_filenm fnm
[])
814 for (i
= 0; (i
< nfile
); i
++)
815 if (ftp
== fnm
[i
].ftp
)
818 return fnm
[i
].nfiles
;
821 fprintf(stderr
, "ftp2fn: No filetype %s\n", deffile
[ftp
].ext
);
825 gmx_bool
ftp2bSet(int ftp
, int nfile
, const t_filenm fnm
[])
829 for (i
= 0; (i
< nfile
); i
++)
830 if (ftp
== fnm
[i
].ftp
)
831 return (gmx_bool
) IS_SET(fnm
[i
]);
833 fprintf(stderr
, "ftp2bSet: No filetype %s\n", deffile
[ftp
].ext
);
838 gmx_bool
opt2bSet(const char *opt
, int nfile
, const t_filenm fnm
[])
842 for (i
= 0; (i
< nfile
); i
++)
843 if (strcmp(opt
, fnm
[i
].opt
) == 0)
844 return (gmx_bool
) IS_SET(fnm
[i
]);
846 fprintf(stderr
, "No option %s\n", opt
);
851 const char *opt2fn_null(const char *opt
, int nfile
, const t_filenm fnm
[])
855 for (i
= 0; (i
< nfile
); i
++)
856 if (strcmp(opt
, fnm
[i
].opt
) == 0)
858 if (IS_OPT(fnm
[i
]) && !IS_SET(fnm
[i
]))
861 return fnm
[i
].fns
[0];
863 fprintf(stderr
, "No option %s\n", opt
);
867 const char *ftp2fn_null(int ftp
, int nfile
, const t_filenm fnm
[])
871 for (i
= 0; (i
< nfile
); i
++)
872 if (ftp
== fnm
[i
].ftp
)
874 if (IS_OPT(fnm
[i
]) && !IS_SET(fnm
[i
]))
877 return fnm
[i
].fns
[0];
879 fprintf(stderr
, "ftp2fn: No filetype %s\n", deffile
[ftp
].ext
);
884 static void add_filters(char *filter
,int *n
,int nf
,const int ftp
[])
889 sprintf(filter
,"*.{");
890 for(i
=0; (i
<nf
); i
++)
892 sprintf(buf
,"%s",ftp2ext(ftp
[i
]));
901 char *ftp2filter(int ftp
)
904 static char filter
[128];
911 add_filters(filter
,&n
,NTRXS
,trxs
);
914 add_filters(filter
,&n
,NTRNS
,trns
);
917 add_filters(filter
,&n
,NSTOS
,stos
);
920 add_filters(filter
,&n
,NSTXS
,stxs
);
923 add_filters(filter
,&n
,NTPXS
,tpxs
);
926 sprintf(filter
,"*%s",ftp2ext(ftp
));
933 gmx_bool
is_optional(const t_filenm
*fnm
)
935 return ((fnm
->flag
& ffOPT
) == ffOPT
);
938 gmx_bool
is_output(const t_filenm
*fnm
)
940 return ((fnm
->flag
& ffWRITE
) == ffWRITE
);
943 gmx_bool
is_set(const t_filenm
*fnm
)
945 return ((fnm
->flag
& ffSET
) == ffSET
);
948 int add_suffix_to_output_names(t_filenm
*fnm
, int nfile
, const char *suffix
)
951 char buf
[STRLEN
], newname
[STRLEN
];
954 for (i
= 0; i
< nfile
; i
++)
956 if (is_output(&fnm
[i
]) && fnm
[i
].ftp
!= efCPT
)
958 /* We never use multiple _outputs_, but we might as well check
959 for it, just in case... */
960 for (j
= 0; j
< fnm
[i
].nfiles
; j
++)
962 strncpy(buf
, fnm
[i
].fns
[j
], STRLEN
- 1);
963 extpos
= strrchr(buf
, '.');
965 sprintf(newname
, "%s%s.%s", buf
, suffix
, extpos
+ 1);
967 fnm
[i
].fns
[j
] = strdup(newname
);
974 t_filenm
*dup_tfn(int nf
, const t_filenm tfn
[])
980 for (i
= 0; i
< nf
; i
++)
982 ret
[i
] = tfn
[i
]; /* just directly copy all non-string fields */
984 ret
[i
].opt
= strdup(tfn
[i
].opt
);
989 ret
[i
].fn
= strdup(tfn
[i
].fn
);
993 if (tfn
[i
].nfiles
> 0)
995 snew(ret
[i
].fns
,tfn
[i
].nfiles
);
996 for (j
= 0; j
< tfn
[i
].nfiles
; j
++)
998 ret
[i
].fns
[j
] = strdup(tfn
[i
].fns
[j
]);
1005 void done_filenms(int nf
, t_filenm fnm
[])
1009 for (i
= 0; i
< nf
; ++i
)
1011 for (j
= 0; j
< fnm
[i
].nfiles
; ++j
)
1013 sfree(fnm
[i
].fns
[j
]);