Replace gmx_large_int_t with gmx_int64_t
[alexxy/gromacs.git] / src / gromacs / gmxlib / readinp.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 <stdio.h>
40 #include <stdlib.h>
41 #include "typedefs.h"
42 #include "string2.h"
43 #include "gromacs/fileio/futil.h"
44 #include "smalloc.h"
45 #include "readinp.h"
46 #include "macros.h"
47 #include "gromacs/fileio/gmxfio.h"
48 #include "names.h"
49 #include "warninp.h"
50 #include "gmx_fatal.h"
51
52 /* find an entry; return index, or -1 if not found */
53 static int search_einp(int ninp, const t_inpfile *inp, const char *name);
54
55
56 t_inpfile *read_inpfile(const char *fn, int *ninp,
57                         warninp_t wi)
58 {
59     FILE      *in;
60     char       buf[STRLEN], lbuf[STRLEN], rbuf[STRLEN], warn_buf[STRLEN];
61     char      *ptr, *cptr;
62     t_inpfile *inp = NULL;
63     int        nin, lc, i, j, k;
64     /* setting cppopts from command-line options would be cooler */
65     gmx_bool   allow_override = FALSE;
66
67
68     if (debug)
69     {
70         fprintf(debug, "Reading MDP file %s\n", fn);
71     }
72
73     in = ffopen(fn, "r");
74
75     nin = lc  = 0;
76     do
77     {
78         ptr = fgets2(buf, STRLEN-1, in);
79         lc++;
80         set_warning_line(wi, fn, lc);
81         if (ptr)
82         {
83             /* Strip comment */
84             if ((cptr = strchr(buf, COMMENTSIGN)) != NULL)
85             {
86                 *cptr = '\0';
87             }
88             /* Strip spaces */
89             trim(buf);
90
91             for (j = 0; (buf[j] != '=') && (buf[j] != '\0'); j++)
92             {
93                 ;
94             }
95             if (buf[j] == '\0')
96             {
97                 if (j > 0)
98                 {
99                     if (debug)
100                     {
101                         fprintf(debug, "No = on line %d in file %s, ignored\n", lc, fn);
102                     }
103                 }
104             }
105             else
106             {
107                 for (i = 0; (i < j); i++)
108                 {
109                     lbuf[i] = buf[i];
110                 }
111                 lbuf[i] = '\0';
112                 trim(lbuf);
113                 if (lbuf[0] == '\0')
114                 {
115                     if (debug)
116                     {
117                         fprintf(debug, "Empty left hand side on line %d in file %s, ignored\n", lc, fn);
118                     }
119                 }
120                 else
121                 {
122                     for (i = j+1, k = 0; (buf[i] != '\0'); i++, k++)
123                     {
124                         rbuf[k] = buf[i];
125                     }
126                     rbuf[k] = '\0';
127                     trim(rbuf);
128                     if (rbuf[0] == '\0')
129                     {
130                         if (debug)
131                         {
132                             fprintf(debug, "Empty right hand side on line %d in file %s, ignored\n", lc, fn);
133                         }
134                     }
135                     else
136                     {
137                         /* Now finally something sensible */
138                         int found_index;
139
140                         /* first check whether we hit the 'multiple_entries' option */
141                         if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptName], lbuf) == 0)
142                         {
143                             /* we now check whether to allow overrides from here or not */
144                             if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptNo], rbuf) == 0)
145                             {
146                                 allow_override = FALSE;
147                             }
148                             else if (gmx_strcasecmp_min(eMultentOpt_names[eMultentOptLast], rbuf) == 0)
149                             {
150                                 allow_override = TRUE;
151                             }
152                             else
153                             {
154                                 sprintf(warn_buf,
155                                         "Parameter \"%s\" should either be %s or %s\n",
156                                         lbuf,
157                                         eMultentOpt_names[eMultentOptNo],
158                                         eMultentOpt_names[eMultentOptLast]);
159                                 warning_error(wi, warn_buf);
160                             }
161                         }
162                         else
163                         {
164                             /* it is a regular option; check for duplicates */
165                             found_index = search_einp(nin, inp, lbuf);
166
167                             if (found_index == -1)
168                             {
169                                 /* add a new item */
170                                 srenew(inp, ++nin);
171                                 inp[nin-1].inp_count  = 1;
172                                 inp[nin-1].count      = 0;
173                                 inp[nin-1].bObsolete  = FALSE;
174                                 inp[nin-1].bSet       = FALSE;
175                                 inp[nin-1].name       = strdup(lbuf);
176                                 inp[nin-1].value      = strdup(rbuf);
177                             }
178                             else
179                             {
180                                 if (!allow_override)
181                                 {
182                                     sprintf(warn_buf,
183                                             "Parameter \"%s\" doubly defined (and multiple assignments not allowed)\n",
184                                             lbuf);
185                                     warning_error(wi, warn_buf);
186                                 }
187                                 else
188                                 {
189                                     /* override */
190                                     sfree(inp[found_index].value);
191                                     inp[found_index].value = strdup(rbuf);
192                                     sprintf(warn_buf,
193                                             "Overriding existing parameter \"%s\" with value \"%s\"\n",
194                                             lbuf, rbuf);
195                                     warning_note(wi, warn_buf);
196                                 }
197                             }
198                         }
199                     }
200                 }
201             }
202         }
203     }
204     while (ptr);
205
206     ffclose(in);
207
208     if (debug)
209     {
210         fprintf(debug, "Done reading MDP file, there were %d entries in there\n",
211                 nin);
212     }
213
214     *ninp = nin;
215
216     return inp;
217 }
218
219
220
221
222 static int inp_comp(const void *a, const void *b)
223 {
224     return ((t_inpfile *)a)->count - ((t_inpfile *)b)->count;
225 }
226
227 static void sort_inp(int ninp, t_inpfile inp[])
228 {
229     int i, mm;
230
231     mm = -1;
232     for (i = 0; (i < ninp); i++)
233     {
234         mm = max(mm, inp[i].count);
235     }
236     for (i = 0; (i < ninp); i++)
237     {
238         if (inp[i].count == 0)
239         {
240             inp[i].count = mm++;
241         }
242     }
243     qsort(inp, ninp, (size_t)sizeof(inp[0]), inp_comp);
244 }
245
246 void write_inpfile(const char *fn, int ninp, t_inpfile inp[], gmx_bool bHaltOnUnknown,
247                    warninp_t wi)
248 {
249     FILE *out;
250     int   i;
251     char  warn_buf[STRLEN];
252
253     sort_inp(ninp, inp);
254     out = gmx_fio_fopen(fn, "w");
255     nice_header(out, fn);
256     for (i = 0; (i < ninp); i++)
257     {
258         if (inp[i].bSet)
259         {
260             if (inp[i].name[0] == ';' || (strlen(inp[i].name) > 2 && inp[i].name[1] == ';'))
261             {
262                 fprintf(out, "%-24s\n", inp[i].name);
263             }
264             else
265             {
266                 fprintf(out, "%-24s = %s\n", inp[i].name, inp[i].value ? inp[i].value : "");
267             }
268         }
269         else if (!inp[i].bObsolete)
270         {
271             sprintf(warn_buf, "Unknown left-hand '%s' in parameter file\n",
272                     inp[i].name);
273             if (bHaltOnUnknown)
274             {
275                 warning_error(wi, warn_buf);
276             }
277             else
278             {
279                 warning(wi, warn_buf);
280             }
281         }
282     }
283     gmx_fio_fclose(out);
284
285     check_warning_error(wi, FARGS);
286 }
287
288 void replace_inp_entry(int ninp, t_inpfile *inp, const char *old_entry, const char *new_entry)
289 {
290     int  i;
291
292     for (i = 0; (i < ninp); i++)
293     {
294         if (gmx_strcasecmp_min(old_entry, inp[i].name) == 0)
295         {
296             if (new_entry)
297             {
298                 fprintf(stderr, "Replacing old mdp entry '%s' by '%s'\n",
299                         inp[i].name, new_entry);
300                 sfree(inp[i].name);
301                 inp[i].name = strdup(new_entry);
302             }
303             else
304             {
305                 fprintf(stderr, "Ignoring obsolete mdp entry '%s'\n",
306                         inp[i].name);
307                 inp[i].bObsolete = TRUE;
308             }
309         }
310     }
311 }
312
313 static int search_einp(int ninp, const t_inpfile *inp, const char *name)
314 {
315     int i;
316
317     if (inp == NULL)
318     {
319         return -1;
320     }
321     for (i = 0; i < ninp; i++)
322     {
323         if (gmx_strcasecmp_min(name, inp[i].name) == 0)
324         {
325             return i;
326         }
327     }
328     return -1;
329 }
330
331 static int get_einp(int *ninp, t_inpfile **inp, const char *name)
332 {
333     int    i;
334     int    notfound = FALSE;
335     char   warn_buf[STRLEN];
336
337 /*  if (inp==NULL)
338     return -1;
339    for(i=0; (i<(*ninp)); i++)
340     if (gmx_strcasecmp_min(name,(*inp)[i].name) == 0)
341       break;
342    if (i == (*ninp)) {*/
343     i = search_einp(*ninp, *inp, name);
344     if (i == -1)
345     {
346         notfound = TRUE;
347         i        = (*ninp)++;
348         srenew(*inp, (*ninp));
349         (*inp)[i].name = strdup(name);
350         (*inp)[i].bSet = TRUE;
351     }
352     (*inp)[i].count = (*inp)[0].inp_count++;
353     (*inp)[i].bSet  = TRUE;
354     if (debug)
355     {
356         fprintf(debug, "Inp %d = %s\n", (*inp)[i].count, (*inp)[i].name);
357     }
358
359     /*if (i == (*ninp)-1)*/
360     if (notfound)
361     {
362         return -1;
363     }
364     else
365     {
366         return i;
367     }
368 }
369
370 int get_eint(int *ninp, t_inpfile **inp, const char *name, int def,
371              warninp_t wi)
372 {
373     char buf[32], *ptr, warn_buf[STRLEN];
374     int  ii;
375     int  ret;
376
377     ii = get_einp(ninp, inp, name);
378
379     if (ii == -1)
380     {
381         sprintf(buf, "%d", def);
382         (*inp)[(*ninp)-1].value = strdup(buf);
383
384         return def;
385     }
386     else
387     {
388         ret = strtol((*inp)[ii].value, &ptr, 10);
389         if (ptr == (*inp)[ii].value)
390         {
391             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);
392             warning_error(wi, warn_buf);
393         }
394
395         return ret;
396     }
397 }
398
399 gmx_int64_t get_eint64(int *ninp, t_inpfile **inp,
400                        const char *name, gmx_int64_t def,
401                        warninp_t wi)
402 {
403     char            buf[32], *ptr, warn_buf[STRLEN];
404     int             ii;
405     gmx_int64_t     ret;
406
407     ii = get_einp(ninp, inp, name);
408
409     if (ii == -1)
410     {
411         sprintf(buf, "%"GMX_PRId64, def);
412         (*inp)[(*ninp)-1].value = strdup(buf);
413
414         return def;
415     }
416     else
417     {
418         ret = str_to_int64_t((*inp)[ii].value, &ptr);
419         if (ptr == (*inp)[ii].value)
420         {
421             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);
422             warning_error(wi, warn_buf);
423         }
424
425         return ret;
426     }
427 }
428
429 double get_ereal(int *ninp, t_inpfile **inp, const char *name, double def,
430                  warninp_t wi)
431 {
432     char   buf[32], *ptr, warn_buf[STRLEN];
433     int    ii;
434     double ret;
435
436     ii = get_einp(ninp, inp, name);
437
438     if (ii == -1)
439     {
440         sprintf(buf, "%g", def);
441         (*inp)[(*ninp)-1].value = strdup(buf);
442
443         return def;
444     }
445     else
446     {
447         ret = strtod((*inp)[ii].value, &ptr);
448         if (ptr == (*inp)[ii].value)
449         {
450             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);
451             warning_error(wi, warn_buf);
452         }
453
454         return ret;
455     }
456 }
457
458 const char *get_estr(int *ninp, t_inpfile **inp, const char *name, const char *def)
459 {
460     char buf[32];
461     int  ii;
462
463     ii = get_einp(ninp, inp, name);
464
465     if (ii == -1)
466     {
467         if (def)
468         {
469             sprintf(buf, "%s", def);
470             (*inp)[(*ninp)-1].value = strdup(buf);
471         }
472         else
473         {
474             (*inp)[(*ninp)-1].value = NULL;
475         }
476
477         return def;
478     }
479     else
480     {
481         return (*inp)[ii].value;
482     }
483 }
484
485 int get_eeenum(int *ninp, t_inpfile **inp, const char *name, const char **defs,
486                warninp_t wi)
487 {
488     int  ii, i, j;
489     int  n = 0;
490     char buf[STRLEN];
491
492     ii = get_einp(ninp, inp, name);
493
494     if (ii == -1)
495     {
496         (*inp)[(*ninp)-1].value = strdup(defs[0]);
497
498         return 0;
499     }
500
501     for (i = 0; (defs[i] != NULL); i++)
502     {
503         if (gmx_strcasecmp_min(defs[i], (*inp)[ii].value) == 0)
504         {
505             break;
506         }
507     }
508
509     if (defs[i] == NULL)
510     {
511         n += sprintf(buf, "Invalid enum '%s' for variable %s, using '%s'\n",
512                      (*inp)[ii].value, name, defs[0]);
513         n += sprintf(buf+n, "Next time use one of:");
514         j  = 0;
515         while (defs[j])
516         {
517             n += sprintf(buf+n, " '%s'", defs[j]);
518             j++;
519         }
520         if (wi != NULL)
521         {
522             warning_error(wi, buf);
523         }
524         else
525         {
526             fprintf(stderr, "%s\n", buf);
527         }
528
529         (*inp)[ii].value = strdup(defs[0]);
530
531         return 0;
532     }
533
534     return i;
535 }
536
537 int get_eenum(int *ninp, t_inpfile **inp, const char *name, const char **defs)
538 {
539     int dum = 0;
540
541     return get_eeenum(ninp, inp, name, defs, NULL);
542 }