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.
52 #include <sys/types.h>
54 #include "gromacs/utility/cstringutil.h"
55 #include "gromacs/utility/dir_separator.h"
56 #include "gromacs/utility/fatalerror.h"
57 #include "gromacs/utility/futil.h"
58 #include "gromacs/utility/gmxassert.h"
59 #include "gromacs/utility/smalloc.h"
67 static t_define *defs = nullptr;
69 static char **incl = nullptr;
71 /* enum used for handling ifdefs */
73 eifTRUE, eifFALSE, eifIGNORE, eifNR
76 typedef struct gmx_cpp {
85 struct gmx_cpp *child, *parent;
88 static bool is_word_end(char c)
90 return !(isalnum(c) || c == '_');
93 static const char *strstrw(const char *buf, const char *word)
97 while ((ptr = strstr(buf, word)) != nullptr)
99 /* Check if we did not find part of a longer word */
101 is_word_end(ptr[strlen(word)]) &&
102 (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
107 buf = ptr + strlen(word);
112 /* Finds a preprocessor directive, whose name (after the '#') is
113 * returned in *name, and the remainder of the line after leading
114 * whitespace is returned in *val (which can be nullptr). */
115 static bool find_directive(char *buf, char **name, char **val)
117 /* Skip initial whitespace */
118 while (isspace(*buf))
122 /* Check if this is a directive */
127 /* Skip the hash and any space after it */
129 while (isspace(*buf))
133 /* Set the name pointer and find the next space */
135 while (*buf != 0 && !isspace(*buf))
139 /* Set the end of the name here, and skip any space */
144 while (isspace(*buf))
149 /* Check if anything is remaining */
150 *val = (*buf != 0) ? buf : nullptr;
154 static bool is_ifdeffed_out(gmx_cpp_t handle)
156 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
159 static void add_include(const char *include)
163 if (include == nullptr)
168 for (i = 0; (i < nincl); i++)
170 if (strcmp(incl[i], include) == 0)
179 incl[nincl-1] = gmx_strdup(include);
183 static void done_includes()
186 for (i = 0; (i < nincl); i++)
195 static void add_define(const char *name, const char *value)
199 for (i = 0; (i < ndef); i++)
201 if (strcmp(defs[i].name, name) == 0)
211 defs[i].name = gmx_strdup(name);
213 else if (defs[i].def)
217 fprintf(debug, "Overriding define %s\n", name);
221 if (value && strlen(value) > 0)
223 defs[i].def = gmx_strdup(value);
227 defs[i].def = nullptr;
231 static void done_defines()
234 for (i = 0; (i < ndef); i++)
244 /* Open the file to be processed. The handle variable holds internal
245 info for the cpp emulator. Return integer status */
246 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
253 /* First process options, they might be necessary for opening files
254 (especially include statements). */
260 if (strstr(cppopts[i], "-I") == cppopts[i])
262 add_include(cppopts[i]+2);
264 if (strstr(cppopts[i], "-D") == cppopts[i])
266 /* If the option contains a =, split it into name and value. */
267 ptr = strchr(cppopts[i], '=');
270 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
271 add_define(buf, ptr + 1);
276 add_define(cppopts[i] + 2, nullptr);
284 fprintf(debug, "GMXCPP: added %d command line arguments\n", i);
290 /* Find the file. First check whether it is in the current directory. */
291 if (gmx_fexist(filenm))
293 cpp->fn = gmx_strdup(filenm);
297 /* If not, check all the paths given with -I. */
298 for (i = 0; i < nincl; ++i)
300 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
301 sprintf(buf, "%s/%s", incl[i], filenm);
309 /* If still not found, check the Gromacs library search path. */
312 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
317 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
319 if (nullptr != debug)
321 fprintf(debug, "GMXCPP: cpp file open %s\n", cpp->fn);
323 /* If the file name has a path component, we need to change to that
324 * directory. Note that we - just as C - always use UNIX path separators
325 * internally in include file names.
327 ptr = strrchr(cpp->fn, '/');
328 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
330 if (ptr == nullptr || (ptr2 != nullptr && ptr2 > ptr))
343 cpp->fn = gmx_strdup(ptr+1);
344 snew(cpp->cwd, STRLEN);
346 gmx_getcwd(cpp->cwd, STRLEN);
347 if (nullptr != debug)
349 fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
351 gmx_chdir(cpp->path);
353 if (nullptr != debug)
355 fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
362 cpp->ifdefs = nullptr;
363 cpp->child = nullptr;
364 cpp->parent = nullptr;
365 if (cpp->fp == nullptr)
367 if (nullptr != debug)
369 fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
371 cpp->fp = fopen(cpp->fn, "r");
373 if (cpp->fp == nullptr)
385 /* Note that dval might be null, e.g. when handling a line like '#define */
387 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
389 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
390 int i, i0, len, status;
396 /* #ifdef or ifndef statement */
397 bIfdef = (strcmp(dname, "ifdef") == 0);
398 bIfndef = (strcmp(dname, "ifndef") == 0);
399 if (bIfdef || bIfndef)
401 GMX_RELEASE_ASSERT(dval, "#ifdef/#ifndef requires an argument");
402 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
405 srenew(handle->ifdefs, handle->nifdef);
406 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
410 // A bare '#ifdef' or '#ifndef' is invalid
415 snew(name, strlen(dval)+1);
416 sscanf(dval, "%s", name);
417 for (i = 0; (i < ndef); i++)
419 if (strcmp(defs[i].name, name) == 0)
425 srenew(handle->ifdefs, handle->nifdef);
426 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
428 handle->ifdefs[handle->nifdef-1] = eifTRUE;
432 handle->ifdefs[handle->nifdef-1] = eifFALSE;
439 /* #else statement */
440 if (strcmp(dname, "else") == 0)
442 if (handle->nifdef <= 0)
446 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
448 handle->ifdefs[handle->nifdef-1] = eifFALSE;
450 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
452 handle->ifdefs[handle->nifdef-1] = eifTRUE;
457 /* #endif statement */
458 if (strcmp(dname, "endif") == 0)
460 if (handle->nifdef <= 0)
468 /* Check whether we're not ifdeffed out. The order of this statement
469 is important. It has to come after #ifdef, #else and #endif, but
470 anything else should be ignored. */
471 if (is_ifdeffed_out(handle))
476 /* Check for include statements */
477 if (strcmp(dname, "include") == 0)
479 GMX_RELEASE_ASSERT(dval, "#include requires an argument");
482 // A bare '#include' is an invalid line
487 for (i1 = 0; (i1 < strlen(dval)); i1++)
489 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
511 strncpy(inc_fn, dval+i0, len);
516 fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
519 /* Open include file and store it as a child in the handle structure */
520 status = cpp_open_file(inc_fn, &(handle->child), nullptr);
522 if (status != eCPP_OK)
524 handle->child = nullptr;
527 /* Make a linked list of open files and move on to the include file */
528 handle->child->parent = handle;
529 *handlep = handle->child;
533 /* #define statement */
534 if (strcmp(dname, "define") == 0)
536 // A bare '#define' is an invalid line
541 /* Split it into name and value. */
543 while ((*ptr != '\0') && !isspace(*ptr))
547 name = gmx_strndup(dval, ptr - dval);
549 while ((*ptr != '\0') && isspace(*ptr))
554 add_define(name, ptr);
559 /* #undef statement */
560 if (strcmp(dname, "undef") == 0)
562 // A bare '#undef' is an invalid line
567 snew(name, strlen(dval)+1);
568 sscanf(dval, "%s", name);
569 for (i = 0; (i < ndef); i++)
571 if (strcmp(defs[i].name, name) == 0)
579 for (; (i < ndef-1); i++)
581 defs[i].name = defs[i+1].name;
582 defs[i].def = defs[i+1].def;
589 /* If we haven't matched anything, this is an unknown directive */
593 /* Return one whole line from the file into buf which holds at most n
594 characters, for subsequent processing. Returns integer status. This
595 routine also does all the "intelligent" work like processing cpp
596 directives and so on. Note that often the routine is called
597 recursively and no cpp directives are printed. */
598 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
600 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
601 int i, nn, len, status;
602 const char *ptr, *ptr2;
609 return eCPP_INVALID_HANDLE;
613 return eCPP_FILE_NOT_OPEN;
616 bEOF = feof(handle->fp);
619 /* Read the actual line now. */
620 if (fgets2(buf, n-1, handle->fp) == nullptr)
622 /* Recheck EOF, since we could have been at the end before
623 * the fgets2 call, but we need to read past the end to know.
625 bEOF = feof(handle->fp);
628 /* Something strange happened, fgets returned NULL,
629 * but we are not at EOF.
638 if (handle->parent == nullptr)
642 cpp_close_file(handlep);
643 *handlep = handle->parent;
644 handle->child = nullptr;
645 return cpp_read_line(handlep, n, buf);
649 if (n > handle->line_len)
651 handle->line_len = n;
652 srenew(handle->line, n);
654 strcpy(handle->line, buf);
657 /* Now we've read a line! */
660 fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
663 /* Process directives if this line contains one */
664 if (find_directive(buf, &dname, &dval))
666 status = process_directive(handlep, dname, dval);
667 if (status != eCPP_OK)
671 /* Don't print lines with directives, go on to the next */
672 return cpp_read_line(handlep, n, buf);
675 /* Check whether we're not ifdeffed out. The order of this statement
676 is important. It has to come after #ifdef, #else and #endif, but
677 anything else should be ignored. */
678 if (is_ifdeffed_out(handle))
680 return cpp_read_line(handlep, n, buf);
683 /* Check whether we have any defines that need to be replaced. Note
684 that we have to use a best fit algorithm, rather than first come
685 first go. We do this by sorting the defines on length first, and
686 then on alphabetical order. */
687 for (i = 0; (i < ndef); i++)
693 while ((ptr = strstrw(ptr, defs[i].name)) != nullptr)
696 ptr += strlen(defs[i].name);
702 len = strlen(buf) + nn*std::max(four, four+strlen(defs[i].def)-strlen(defs[i].name));
705 while ((ptr2 = strstrw(ptr, defs[i].name)) != nullptr)
707 strncat(name, ptr, (int)(ptr2-ptr));
708 strcat(name, defs[i].def);
709 ptr = ptr2 + strlen(defs[i].name);
721 char *cpp_cur_file(const gmx_cpp_t *handlep)
723 return (*handlep)->fn;
726 int cpp_cur_linenr(const gmx_cpp_t *handlep)
728 return (*handlep)->line_nr;
731 /* Close the file! Return integer status. */
732 int cpp_close_file(gmx_cpp_t *handlep)
734 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
738 return eCPP_INVALID_HANDLE;
742 return eCPP_FILE_NOT_OPEN;
746 fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
749 if (nullptr != handle->cwd)
751 if (nullptr != debug)
753 fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
755 gmx_chdir(handle->cwd);
765 return eCPP_FILE_NOT_FOUND;
767 return eCPP_FILE_NOT_OPEN;
769 return eCPP_INTERRUPT;
773 fprintf(debug, "Strange stuff closing file, errno = %d", errno);
778 handle->fp = nullptr;
780 if (nullptr != handle->fn)
783 handle->fn = nullptr;
785 if (nullptr != handle->line)
788 handle->line = nullptr;
790 if (nullptr != handle->ifdefs)
792 sfree(handle->ifdefs);
795 if (nullptr != handle->path)
799 if (nullptr != handle->cwd)
813 /* Return a string containing the error message coresponding to status
815 char *cpp_error(gmx_cpp_t *handlep, int status)
818 const char *ecpp[] = {
819 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
820 "Invalid file handle",
821 "File not open", "Unknown error", "Error status out of range"
823 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
827 return (char *)ecpp[eCPP_INVALID_HANDLE];
830 if ((status < 0) || (status >= eCPP_NR))
835 sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
837 (handle && handle->fn) ? handle->fn : "unknown",
838 (handle) ? handle->line_nr : -1,
839 handle->line ? handle->line : "");
841 return gmx_strdup(buf);