Fix grompp memory leaks
[gromacs.git] / src / gromacs / gmxpreprocess / gmxcpp.cpp
blob2dd129a41abb2be4eb3720234dc5ea016f026ef4
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2017,2018, 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.
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.
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.
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.
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.
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.
37 #include "gmxpre.h"
39 #include "gmxcpp.h"
41 #include <cctype>
42 #include <cerrno>
43 #include <climits>
44 #include <cmath>
45 #include <cstdio>
46 #include <cstdlib>
47 #include <cstring>
49 #include <algorithm>
51 #include <sys/types.h>
53 #include "gromacs/utility/cstringutil.h"
54 #include "gromacs/utility/dir_separator.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/futil.h"
57 #include "gromacs/utility/gmxassert.h"
58 #include "gromacs/utility/smalloc.h"
60 typedef struct {
61 char *name;
62 char *def;
63 } t_define;
65 static int ndef = 0;
66 static t_define *defs = nullptr;
67 static int nincl = 0;
68 static char **incl = nullptr;
70 /* enum used for handling ifdefs */
71 enum {
72 eifTRUE, eifFALSE, eifIGNORE, eifNR
75 typedef struct gmx_cpp {
76 FILE *fp;
77 char *path, *cwd;
78 char *fn;
79 int line_len;
80 char *line;
81 int line_nr;
82 int nifdef;
83 int *ifdefs;
84 struct gmx_cpp *child, *parent;
85 } gmx_cpp;
87 static bool is_word_end(char c)
89 return !((isalnum(c) != 0) || c == '_');
92 static const char *strstrw(const char *buf, const char *word)
94 const char *ptr;
96 while ((ptr = strstr(buf, word)) != nullptr)
98 /* Check if we did not find part of a longer word */
99 if (ptr &&
100 is_word_end(ptr[strlen(word)]) &&
101 (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
103 return ptr;
106 buf = ptr + strlen(word);
108 return nullptr;
111 /* Finds a preprocessor directive, whose name (after the '#') is
112 * returned in *name, and the remainder of the line after leading
113 * whitespace is returned in *val (which can be nullptr). */
114 static bool find_directive(char *buf, char **name, char **val)
116 /* Skip initial whitespace */
117 while (isspace(*buf))
119 ++buf;
121 /* Check if this is a directive */
122 if (*buf != '#')
124 return FALSE;
126 /* Skip the hash and any space after it */
127 ++buf;
128 while (isspace(*buf))
130 ++buf;
132 /* Set the name pointer and find the next space */
133 *name = buf;
134 while (*buf != 0 && !isspace(*buf))
136 ++buf;
138 /* Set the end of the name here, and skip any space */
139 if (*buf != 0)
141 *buf = 0;
142 ++buf;
143 while (isspace(*buf))
145 ++buf;
148 /* Check if anything is remaining */
149 *val = (*buf != 0) ? buf : nullptr;
150 return TRUE;
153 static bool is_ifdeffed_out(gmx_cpp_t handle)
155 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
158 static void add_include(const char *include)
160 int i;
162 if (include == nullptr)
164 return;
167 for (i = 0; (i < nincl); i++)
169 if (strcmp(incl[i], include) == 0)
171 break;
174 if (i == nincl)
176 nincl++;
177 srenew(incl, nincl);
178 incl[nincl-1] = gmx_strdup(include);
182 static void done_includes()
184 int i;
185 for (i = 0; (i < nincl); i++)
187 sfree(incl[i]);
189 sfree(incl);
190 incl = nullptr;
191 nincl = 0;
194 static void add_define(const char *name, const char *value)
196 int i;
198 for (i = 0; (i < ndef); i++)
200 if (strcmp(defs[i].name, name) == 0)
202 break;
205 if (i == ndef)
207 ndef++;
208 srenew(defs, ndef);
209 i = ndef - 1;
210 defs[i].name = gmx_strdup(name);
212 else if (defs[i].def)
214 sfree(defs[i].def);
216 if (value && strlen(value) > 0)
218 defs[i].def = gmx_strdup(value);
220 else
222 defs[i].def = nullptr;
226 static void done_defines()
228 int i;
229 for (i = 0; (i < ndef); i++)
231 sfree(defs[i].name);
232 sfree(defs[i].def);
234 sfree(defs);
235 defs = nullptr;
236 ndef = 0;
239 /* Open the file to be processed. The handle variable holds internal
240 info for the cpp emulator. Return integer status */
241 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
243 gmx_cpp_t cpp;
244 char *buf;
245 char *ptr, *ptr2;
246 int i;
248 /* First process options, they might be necessary for opening files
249 (especially include statements). */
250 i = 0;
251 if (cppopts)
253 while (cppopts[i])
255 if (strstr(cppopts[i], "-I") == cppopts[i])
257 add_include(cppopts[i]+2);
259 if (strstr(cppopts[i], "-D") == cppopts[i])
261 /* If the option contains a =, split it into name and value. */
262 ptr = strchr(cppopts[i], '=');
263 if (ptr)
265 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
266 add_define(buf, ptr + 1);
267 sfree(buf);
269 else
271 add_define(cppopts[i] + 2, nullptr);
274 i++;
278 snew(cpp, 1);
279 *handle = cpp;
280 cpp->fn = nullptr;
281 /* Find the file. First check whether it is in the current directory. */
282 if (gmx_fexist(filenm))
284 cpp->fn = gmx_strdup(filenm);
286 else
288 /* If not, check all the paths given with -I. */
289 for (i = 0; i < nincl; ++i)
291 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
292 sprintf(buf, "%s/%s", incl[i], filenm);
293 if (gmx_fexist(buf))
295 cpp->fn = buf;
296 break;
298 sfree(buf);
300 /* If still not found, check the Gromacs library search path. */
301 if (!cpp->fn)
303 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
306 if (!cpp->fn)
308 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
310 /* If the file name has a path component, we need to change to that
311 * directory. Note that we - just as C - always use UNIX path separators
312 * internally in include file names.
314 ptr = strrchr(cpp->fn, '/');
315 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
317 if (ptr == nullptr || (ptr2 != nullptr && ptr2 > ptr))
319 ptr = ptr2;
321 if (ptr == nullptr)
323 cpp->path = nullptr;
324 cpp->cwd = nullptr;
326 else
328 cpp->path = cpp->fn;
329 *ptr = '\0';
330 cpp->fn = gmx_strdup(ptr+1);
331 snew(cpp->cwd, STRLEN);
333 gmx_getcwd(cpp->cwd, STRLEN);
334 gmx_chdir(cpp->path);
336 cpp->line_len = 0;
337 cpp->line = nullptr;
338 cpp->line_nr = 0;
339 cpp->nifdef = 0;
340 cpp->ifdefs = nullptr;
341 cpp->child = nullptr;
342 cpp->parent = nullptr;
343 if (cpp->fp == nullptr)
345 cpp->fp = fopen(cpp->fn, "r");
347 if (cpp->fp == nullptr)
349 switch (errno)
351 case EINVAL:
352 default:
353 return eCPP_UNKNOWN;
356 return eCPP_OK;
359 /* Note that dval might be null, e.g. when handling a line like '#define */
360 static int
361 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
363 gmx_cpp_t handle = *handlep;
364 int i, i0, len, status;
365 unsigned int i1;
366 char *inc_fn, *name;
367 const char *ptr;
368 bool bIfdef, bIfndef;
370 /* #ifdef or ifndef statement */
371 bIfdef = strcmp(dname, "ifdef") == 0;
372 bIfndef = strcmp(dname, "ifndef") == 0;
373 if (bIfdef || bIfndef)
375 GMX_RELEASE_ASSERT(dval, "#ifdef/#ifndef requires an argument");
376 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
378 handle->nifdef++;
379 srenew(handle->ifdefs, handle->nifdef);
380 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
382 else
384 // A bare '#ifdef' or '#ifndef' is invalid
385 if (dval == nullptr)
387 return eCPP_SYNTAX;
389 snew(name, strlen(dval)+1);
390 sscanf(dval, "%s", name);
391 for (i = 0; (i < ndef); i++)
393 if (strcmp(defs[i].name, name) == 0)
395 break;
398 handle->nifdef++;
399 srenew(handle->ifdefs, handle->nifdef);
400 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
402 handle->ifdefs[handle->nifdef-1] = eifTRUE;
404 else
406 handle->ifdefs[handle->nifdef-1] = eifFALSE;
408 sfree(name);
410 return eCPP_OK;
413 /* #else statement */
414 if (strcmp(dname, "else") == 0)
416 if (handle->nifdef <= 0)
418 return eCPP_SYNTAX;
420 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
422 handle->ifdefs[handle->nifdef-1] = eifFALSE;
424 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
426 handle->ifdefs[handle->nifdef-1] = eifTRUE;
428 return eCPP_OK;
431 /* #endif statement */
432 if (strcmp(dname, "endif") == 0)
434 if (handle->nifdef <= 0)
436 return eCPP_SYNTAX;
438 handle->nifdef--;
439 return eCPP_OK;
442 /* Check whether we're not ifdeffed out. The order of this statement
443 is important. It has to come after #ifdef, #else and #endif, but
444 anything else should be ignored. */
445 if (is_ifdeffed_out(handle))
447 return eCPP_OK;
450 /* Check for include statements */
451 if (strcmp(dname, "include") == 0)
453 GMX_RELEASE_ASSERT(dval, "#include requires an argument");
454 len = -1;
455 i0 = 0;
456 // A bare '#include' is an invalid line
457 if (dval == nullptr)
459 return eCPP_SYNTAX;
461 for (i1 = 0; (i1 < strlen(dval)); i1++)
463 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
465 if (len == -1)
467 i0 = i1+1;
468 len = 0;
470 else
472 break;
475 else if (len >= 0)
477 len++;
480 if (len == -1)
482 return eCPP_SYNTAX;
484 snew(inc_fn, len+1);
485 strncpy(inc_fn, dval+i0, len);
486 inc_fn[len] = '\0';
488 /* Open include file and store it as a child in the handle structure */
489 status = cpp_open_file(inc_fn, &(handle->child), nullptr);
490 sfree(inc_fn);
491 if (status != eCPP_OK)
493 handle->child = nullptr;
494 return status;
496 /* Make a linked list of open files and move on to the include file */
497 handle->child->parent = handle;
498 *handlep = handle->child;
499 return eCPP_OK;
502 /* #define statement */
503 if (strcmp(dname, "define") == 0)
505 // A bare '#define' is an invalid line
506 if (dval == nullptr)
508 return eCPP_SYNTAX;
510 /* Split it into name and value. */
511 ptr = dval;
512 while ((*ptr != '\0') && !isspace(*ptr))
514 ptr++;
516 name = gmx_strndup(dval, ptr - dval);
518 while ((*ptr != '\0') && isspace(*ptr))
520 ptr++;
523 add_define(name, ptr);
524 sfree(name);
525 return eCPP_OK;
528 /* #undef statement */
529 if (strcmp(dname, "undef") == 0)
531 // A bare '#undef' is an invalid line
532 if (dval == nullptr)
534 return eCPP_SYNTAX;
536 snew(name, strlen(dval)+1);
537 sscanf(dval, "%s", name);
538 for (i = 0; (i < ndef); i++)
540 if (strcmp(defs[i].name, name) == 0)
542 sfree(defs[i].name);
543 sfree(defs[i].def);
544 break;
547 sfree(name);
548 for (; (i < ndef-1); i++)
550 defs[i].name = defs[i+1].name;
551 defs[i].def = defs[i+1].def;
553 ndef--;
555 return eCPP_OK;
558 /* If we haven't matched anything, this is an unknown directive */
559 return eCPP_SYNTAX;
562 /* Return one whole line from the file into buf which holds at most n
563 characters, for subsequent processing. Returns integer status. This
564 routine also does all the "intelligent" work like processing cpp
565 directives and so on. Note that often the routine is called
566 recursively and no cpp directives are printed. */
567 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
569 gmx_cpp_t handle = *handlep;
570 int i, nn, len, status;
571 const char *ptr, *ptr2;
572 char *name;
573 char *dname, *dval;
574 bool bEOF;
576 if (!handle)
578 return eCPP_INVALID_HANDLE;
580 if (!handle->fp)
582 return eCPP_FILE_NOT_OPEN;
585 bEOF = (feof(handle->fp) != 0);
586 if (!bEOF)
588 /* Read the actual line now. */
589 if (fgets2(buf, n-1, handle->fp) == nullptr)
591 /* Recheck EOF, since we could have been at the end before
592 * the fgets2 call, but we need to read past the end to know.
594 bEOF = (feof(handle->fp) != 0);
595 if (!bEOF)
597 /* Something strange happened, fgets returned NULL,
598 * but we are not at EOF.
600 return eCPP_UNKNOWN;
605 if (bEOF)
607 if (handle->parent == nullptr)
609 return eCPP_EOF;
611 cpp_close_file(handlep);
612 *handlep = handle->parent;
613 handle->child = nullptr;
614 sfree(handle);
615 return cpp_read_line(handlep, n, buf);
617 else
619 if (n > handle->line_len)
621 handle->line_len = n;
622 srenew(handle->line, n);
624 strcpy(handle->line, buf);
625 handle->line_nr++;
626 } /* Now we've read a line! */
628 /* Process directives if this line contains one */
629 if (find_directive(buf, &dname, &dval))
631 status = process_directive(handlep, dname, dval);
632 if (status != eCPP_OK)
634 return status;
636 /* Don't print lines with directives, go on to the next */
637 return cpp_read_line(handlep, n, buf);
640 /* Check whether we're not ifdeffed out. The order of this statement
641 is important. It has to come after #ifdef, #else and #endif, but
642 anything else should be ignored. */
643 if (is_ifdeffed_out(handle))
645 return cpp_read_line(handlep, n, buf);
648 /* Check whether we have any defines that need to be replaced. Note
649 that we have to use a best fit algorithm, rather than first come
650 first go. We do this by sorting the defines on length first, and
651 then on alphabetical order. */
652 for (i = 0; (i < ndef); i++)
654 if (defs[i].def)
656 nn = 0;
657 ptr = buf;
658 while ((ptr = strstrw(ptr, defs[i].name)) != nullptr)
660 nn++;
661 ptr += strlen(defs[i].name);
663 if (nn > 0)
665 size_t four = 4;
667 len = strlen(buf) + nn*std::max(four, four+strlen(defs[i].def)-strlen(defs[i].name));
668 snew(name, len);
669 ptr = buf;
670 while ((ptr2 = strstrw(ptr, defs[i].name)) != nullptr)
672 strncat(name, ptr, static_cast<int>(ptr2-ptr));
673 strcat(name, defs[i].def);
674 ptr = ptr2 + strlen(defs[i].name);
676 strcat(name, ptr);
677 strcpy(buf, name);
678 sfree(name);
683 return eCPP_OK;
686 char *cpp_cur_file(const gmx_cpp_t *handlep)
688 return (*handlep)->fn;
691 int cpp_cur_linenr(const gmx_cpp_t *handlep)
693 return (*handlep)->line_nr;
696 /* Close the file! Return integer status. */
697 int cpp_close_file(gmx_cpp_t *handlep)
699 gmx_cpp_t handle = *handlep;
701 if (!handle)
703 return eCPP_INVALID_HANDLE;
705 if (!handle->fp)
707 return eCPP_FILE_NOT_OPEN;
709 fclose(handle->fp);
710 if (nullptr != handle->cwd)
712 gmx_chdir(handle->cwd);
715 handle->fp = nullptr;
716 handle->line_nr = 0;
717 if (nullptr != handle->fn)
719 sfree(handle->fn);
720 handle->fn = nullptr;
722 if (nullptr != handle->line)
724 sfree(handle->line);
725 handle->line = nullptr;
727 if (nullptr != handle->ifdefs)
729 sfree(handle->ifdefs);
731 handle->nifdef = 0;
732 if (nullptr != handle->path)
734 sfree(handle->path);
736 if (nullptr != handle->cwd)
738 sfree(handle->cwd);
741 return eCPP_OK;
744 void cpp_done(gmx_cpp_t handle)
746 done_includes();
747 done_defines();
749 int status = cpp_close_file(&handle);
750 if (status != eCPP_OK)
752 gmx_fatal(FARGS, "%s", cpp_error(&handle, status));
754 sfree(handle);
757 /* Return a string containing the error message coresponding to status
758 variable */
759 char *cpp_error(gmx_cpp_t *handlep, int status)
761 char buf[256];
762 const char *ecpp[] = {
763 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
764 "Invalid file handle",
765 "File not open", "Unknown error", "Error status out of range"
767 gmx_cpp_t handle = *handlep;
769 if (!handle)
771 return const_cast<char *>(ecpp[eCPP_INVALID_HANDLE]);
774 if ((status < 0) || (status >= eCPP_NR))
776 status = eCPP_NR;
779 sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
780 ecpp[status],
781 (handle && handle->fn) ? handle->fn : "unknown",
782 (handle) ? handle->line_nr : -1,
783 handle->line ? handle->line : "");
785 return gmx_strdup(buf);