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