Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / gmxlib / readinp.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include "typedefs.h"
45 #include "string2.h"
46 #include "futil.h"
47 #include "smalloc.h"
48 #include "readinp.h"
49 #include "macros.h"
50 #include "statutil.h"
51 #include "gmxfio.h"
52 #include "names.h"
53 #include "warninp.h"
54 #include "gmx_fatal.h"
55
56 /* find an entry; return index, or -1 if not found */
57 static int search_einp(int ninp, const t_inpfile *inp, const char *name);
58
59
60 t_inpfile *read_inpfile(const char *fn,int *ninp, 
61                         char **cppopts,
62                         warninp_t wi)
63 {
64   FILE      *in;
65   char      buf[STRLEN],lbuf[STRLEN],rbuf[STRLEN],warn_buf[STRLEN];
66   char      *ptr,*cptr;
67   t_inpfile *inp=NULL;
68   int       nin,lc,i,j,k;
69   /* setting cppopts from command-line options would be cooler */
70   gmx_bool allow_override=FALSE;
71
72     
73   if (debug)
74     fprintf(debug,"Reading MDP file %s\n",fn);
75     
76   in = ffopen(fn, "r");
77
78   nin = lc  = 0;
79   do {
80     ptr = fgets2(buf,STRLEN-1,in);
81     lc++;
82     set_warning_line(wi,fn,lc);
83     if (ptr) {
84       /* Strip comment */
85       if ((cptr=strchr(buf,COMMENTSIGN)) != NULL)
86         *cptr='\0';
87       /* Strip spaces */
88       trim(buf);
89       
90       for(j=0; (buf[j] != '=') && (buf[j] != '\0'); j++)
91         ;
92       if (buf[j] == '\0') {
93         if (j > 0) {
94           if (debug)
95             fprintf(debug,"No = on line %d in file %s, ignored\n",lc,fn);
96         }
97       }
98       else {
99         for(i=0; (i<j); i++)
100           lbuf[i]=buf[i];
101         lbuf[i]='\0';
102         trim(lbuf);
103         if (lbuf[0] == '\0') {
104           if (debug) 
105             fprintf(debug,"Empty left hand side on line %d in file %s, ignored\n",lc,fn);
106         }
107         else {
108           for(i=j+1,k=0; (buf[i] != '\0'); i++,k++)
109             rbuf[k]=buf[i];
110           rbuf[k]='\0';
111           trim(rbuf);
112           if (rbuf[0] == '\0') {
113             if (debug)
114               fprintf(debug,"Empty right hand side on line %d in file %s, ignored\n",lc,fn);
115           }
116           else {
117             /* Now finally something sensible */
118             int found_index;
119             
120             /* first check whether we hit the 'multiple_entries' option */
121             if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptName], lbuf)==0) 
122             {
123               /* we now check whether to allow overrides from here or not */
124               if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptNo], rbuf)==0)
125               {
126                 allow_override=FALSE;
127               }
128               else if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptLast], rbuf)==0)
129               {
130                 allow_override=TRUE;
131               }
132               else
133               {
134                 sprintf(warn_buf,
135                         "Parameter \"%s\" should either be %s or %s\n",
136                         lbuf,
137                         eMultentOpt_names[eMultentOptNo],
138                         eMultentOpt_names[eMultentOptLast]);
139                 warning_error(wi,warn_buf);
140               }
141             }
142             else
143             {
144               /* it is a regular option; check for duplicates */
145               found_index=search_einp(nin, inp, lbuf);
146               
147               if (found_index == -1)
148               {
149                 /* add a new item */
150                 srenew(inp,++nin);
151                 inp[nin-1].inp_count  = 1;
152                 inp[nin-1].count      = 0;
153                 inp[nin-1].bObsolete  = FALSE;
154                 inp[nin-1].bSet       = FALSE;
155                 inp[nin-1].name       = strdup(lbuf);
156                 inp[nin-1].value      = strdup(rbuf);
157               }
158               else
159               {
160                 if (!allow_override)
161                 {
162                   sprintf(warn_buf,
163                           "Parameter \"%s\" doubly defined (and multiple assignments not allowed)\n",
164                           lbuf);
165                   warning_error(wi,warn_buf);
166                 }
167                 else
168                 {
169                   /* override */
170                   sfree(inp[found_index].value);
171                   inp[found_index].value = strdup(rbuf);
172                   sprintf(warn_buf,
173                           "Overriding existing parameter \"%s\" with value \"%s\"\n",
174                           lbuf,rbuf);
175                   warning_note(wi,warn_buf);
176                 }
177               }
178             }
179           }
180         }
181       }
182     }
183   } while (ptr);
184   
185   ffclose(in);
186
187   if (debug) {
188     fprintf(debug,"Done reading MDP file, there were %d entries in there\n",
189             nin);
190   }
191
192   *ninp = nin;
193
194   return inp;
195 }
196
197         
198                   
199
200 static int inp_comp(const void *a,const void *b)
201 {
202   return ((t_inpfile *)a)->count - ((t_inpfile *)b)->count;
203 }
204
205 static void sort_inp(int ninp,t_inpfile inp[])
206 {
207   int i,mm;
208   
209   mm=-1;
210   for(i=0; (i<ninp); i++)
211     mm=max(mm,inp[i].count);
212   for(i=0; (i<ninp); i++) {
213     if (inp[i].count == 0)
214       inp[i].count = mm++;
215   }
216   qsort(inp,ninp,(size_t)sizeof(inp[0]),inp_comp);
217 }
218
219 void write_inpfile(const char *fn,int ninp,t_inpfile inp[],gmx_bool bHaltOnUnknown,
220                    warninp_t wi)
221 {
222   FILE *out;
223   int  i;
224   char warn_buf[STRLEN];
225
226   sort_inp(ninp,inp);  
227   out=gmx_fio_fopen(fn,"w");
228   nice_header(out,fn);
229   for(i=0; (i<ninp); i++) {
230     if (inp[i].bSet) {
231       if(inp[i].name[0]==';' || (strlen(inp[i].name)>2 && inp[i].name[1]==';'))
232         fprintf(out,"%-24s\n",inp[i].name);
233       else
234         fprintf(out,"%-24s = %s\n",inp[i].name,inp[i].value ? inp[i].value : "");
235     } else if (!inp[i].bObsolete) {
236       sprintf(warn_buf,"Unknown left-hand '%s' in parameter file\n",
237               inp[i].name);
238       if (bHaltOnUnknown) {
239         warning_error(wi,warn_buf);
240       } else {
241         warning(wi,warn_buf);
242       }
243     }
244   }
245   gmx_fio_fclose(out);
246
247   check_warning_error(wi,FARGS);
248 }
249
250 void replace_inp_entry(int ninp,t_inpfile *inp,const char *old_entry,const char *new_entry)
251 {
252   int  i;
253   
254   for(i=0; (i<ninp); i++) {
255     if (gmx_strcasecmp_min(old_entry,inp[i].name) == 0) {
256       if (new_entry) {
257         fprintf(stderr,"Replacing old mdp entry '%s' by '%s'\n",
258                 inp[i].name,new_entry);
259         sfree(inp[i].name);
260         inp[i].name = strdup(new_entry);
261       } else {
262         fprintf(stderr,"Ignoring obsolete mdp entry '%s'\n",
263                 inp[i].name);
264         inp[i].bObsolete = TRUE;
265       }
266     }
267   }
268 }
269
270 static int search_einp(int ninp, const t_inpfile *inp, const char *name)
271 {
272   int i;
273   
274   if (inp==NULL)
275     return -1;
276   for(i=0; i<ninp; i++)
277     if (gmx_strcasecmp_min(name,inp[i].name) == 0)
278       return i;
279   return -1;
280 }
281
282 static int get_einp(int *ninp,t_inpfile **inp,const char *name)
283 {
284   int    i;
285   int    notfound=FALSE;
286   char   warn_buf[STRLEN];
287
288 /*  if (inp==NULL)
289     return -1;
290   for(i=0; (i<(*ninp)); i++)
291     if (gmx_strcasecmp_min(name,(*inp)[i].name) == 0)
292       break;
293   if (i == (*ninp)) {*/
294   i=search_einp(*ninp, *inp, name);
295   if (i == -1)
296   {
297     notfound=TRUE;
298     i=(*ninp)++;
299     srenew(*inp,(*ninp));
300     (*inp)[i].name=strdup(name);
301     (*inp)[i].bSet=TRUE;
302   }
303   (*inp)[i].count = (*inp)[0].inp_count++;
304   (*inp)[i].bSet  = TRUE;
305   if (debug) 
306     fprintf(debug,"Inp %d = %s\n",(*inp)[i].count,(*inp)[i].name);
307   
308   /*if (i == (*ninp)-1)*/
309   if (notfound)
310     return -1;
311   else
312     return i;
313 }
314
315 int get_eint(int *ninp,t_inpfile **inp,const char *name,int def,
316              warninp_t wi)
317 {
318   char buf[32],*ptr,warn_buf[STRLEN];
319   int  ii;
320   int  ret;
321   
322   ii=get_einp(ninp,inp,name);
323   
324   if (ii == -1) {
325     sprintf(buf,"%d",def);
326     (*inp)[(*ninp)-1].value=strdup(buf);
327     
328     return def;
329   }
330   else {
331     ret = strtol((*inp)[ii].value,&ptr,10);
332     if (ptr == (*inp)[ii].value) {
333       sprintf(warn_buf,"Right hand side '%s' for parameter '%s' in parameter file is not an integer value\n",(*inp)[ii].value,(*inp)[ii].name);
334       warning_error(wi,warn_buf);
335     }
336
337     return ret;
338   }
339 }
340
341 gmx_large_int_t get_egmx_large_int(int *ninp,t_inpfile **inp,
342                                    const char *name,gmx_large_int_t def,
343                                    warninp_t wi)
344 {
345   char buf[32],*ptr,warn_buf[STRLEN];
346   int  ii;
347   gmx_large_int_t ret;
348   
349   ii=get_einp(ninp,inp,name);
350   
351   if (ii == -1) {
352     sprintf(buf,gmx_large_int_pfmt,def);
353     (*inp)[(*ninp)-1].value=strdup(buf);
354     
355     return def;
356   }
357   else {
358     ret = str_to_large_int_t((*inp)[ii].value,&ptr);
359     if (ptr == (*inp)[ii].value) {
360       sprintf(warn_buf,"Right hand side '%s' for parameter '%s' in parameter file is not an integer value\n",(*inp)[ii].value,(*inp)[ii].name);
361       warning_error(wi,warn_buf);
362     }
363
364     return ret;
365   }
366 }
367
368 double get_ereal(int *ninp,t_inpfile **inp,const char *name,double def,
369                  warninp_t wi)
370 {
371   char buf[32],*ptr,warn_buf[STRLEN];
372   int  ii;
373   double ret;
374   
375   ii=get_einp(ninp,inp,name);
376   
377   if (ii == -1) {
378     sprintf(buf,"%g",def);
379     (*inp)[(*ninp)-1].value=strdup(buf);
380     
381     return def;
382   }
383   else {
384     ret = strtod((*inp)[ii].value,&ptr);
385     if (ptr == (*inp)[ii].value) {
386       sprintf(warn_buf,"Right hand side '%s' for parameter '%s' in parameter file is not a real value\n",(*inp)[ii].value,(*inp)[ii].name);
387       warning_error(wi,warn_buf);
388     }
389
390     return ret;
391   }
392 }
393
394 const char *get_estr(int *ninp,t_inpfile **inp,const char *name,const char *def)
395 {
396   char buf[32];
397   int  ii;
398   
399   ii=get_einp(ninp,inp,name);
400   
401   if (ii == -1) {
402     if (def) {
403       sprintf(buf,"%s",def);
404       (*inp)[(*ninp)-1].value=strdup(buf);
405     }
406     else
407       (*inp)[(*ninp)-1].value=NULL;
408       
409     return def;
410   }
411   else 
412     return (*inp)[ii].value;
413 }
414
415 int get_eeenum(int *ninp,t_inpfile **inp,const char *name,const char **defs,
416                warninp_t wi)
417 {
418   int  ii,i,j;
419   int n=0;
420   char buf[STRLEN];
421   
422   ii=get_einp(ninp,inp,name);
423   
424   if (ii == -1) {
425     (*inp)[(*ninp)-1].value=strdup(defs[0]);
426     
427     return 0;
428   }
429   
430   for(i=0; (defs[i] != NULL); i++)
431     if (gmx_strcasecmp_min(defs[i],(*inp)[ii].value) == 0)
432       break;
433   
434   if (defs[i] == NULL) {
435     n += sprintf(buf,"Invalid enum '%s' for variable %s, using '%s'\n",
436                 (*inp)[ii].value,name,defs[0]);
437     n += sprintf(buf+n,"Next time use one of:");
438     j=0;
439     while (defs[j]) {
440       n += sprintf(buf+n," '%s'",defs[j]);
441       j++;
442     }
443     if (wi != NULL) {
444       warning_error(wi,buf);
445     } else {
446       fprintf(stderr,"%s\n",buf);
447     }
448
449     (*inp)[ii].value = strdup(defs[0]);
450     
451     return 0;
452   }
453   
454   return i;
455 }
456
457 int get_eenum(int *ninp,t_inpfile **inp,const char *name,const char **defs)
458 {
459   int dum=0;
460
461   return get_eeenum(ninp,inp,name,defs,NULL);
462 }
463