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 static bool find_directive(char *buf, char **name, char **val)
114 /* Skip initial whitespace */
115 while (isspace(*buf))
119 /* Check if this is a directive */
124 /* Skip the hash and any space after it */
126 while (isspace(*buf))
130 /* Set the name pointer and find the next space */
132 while (*buf != 0 && !isspace(*buf))
136 /* Set the end of the name here, and skip any space */
141 while (isspace(*buf))
146 /* Check if anything is remaining */
147 *val = (*buf != 0) ? buf : nullptr;
151 static bool is_ifdeffed_out(gmx_cpp_t handle)
153 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
156 static void add_include(const char *include)
160 if (include == nullptr)
165 for (i = 0; (i < nincl); i++)
167 if (strcmp(incl[i], include) == 0)
176 incl[nincl-1] = gmx_strdup(include);
180 static void done_includes()
183 for (i = 0; (i < nincl); i++)
192 static void add_define(const char *name, const char *value)
196 for (i = 0; (i < ndef); i++)
198 if (strcmp(defs[i].name, name) == 0)
208 defs[i].name = gmx_strdup(name);
210 else if (defs[i].def)
214 fprintf(debug, "Overriding define %s\n", name);
218 if (value && strlen(value) > 0)
220 defs[i].def = gmx_strdup(value);
224 defs[i].def = nullptr;
228 static void done_defines()
231 for (i = 0; (i < ndef); i++)
241 /* Open the file to be processed. The handle variable holds internal
242 info for the cpp emulator. Return integer status */
243 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
250 /* First process options, they might be necessary for opening files
251 (especially include statements). */
257 if (strstr(cppopts[i], "-I") == cppopts[i])
259 add_include(cppopts[i]+2);
261 if (strstr(cppopts[i], "-D") == cppopts[i])
263 /* If the option contains a =, split it into name and value. */
264 ptr = strchr(cppopts[i], '=');
267 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
268 add_define(buf, ptr + 1);
273 add_define(cppopts[i] + 2, nullptr);
281 fprintf(debug, "GMXCPP: added %d command line arguments\n", i);
287 /* Find the file. First check whether it is in the current directory. */
288 if (gmx_fexist(filenm))
290 cpp->fn = gmx_strdup(filenm);
294 /* If not, check all the paths given with -I. */
295 for (i = 0; i < nincl; ++i)
297 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
298 sprintf(buf, "%s/%s", incl[i], filenm);
306 /* If still not found, check the Gromacs library search path. */
309 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
314 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
316 if (nullptr != debug)
318 fprintf(debug, "GMXCPP: cpp file open %s\n", cpp->fn);
320 /* If the file name has a path component, we need to change to that
321 * directory. Note that we - just as C - always use UNIX path separators
322 * internally in include file names.
324 ptr = strrchr(cpp->fn, '/');
325 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
327 if (ptr == nullptr || (ptr2 != nullptr && ptr2 > ptr))
340 cpp->fn = gmx_strdup(ptr+1);
341 snew(cpp->cwd, STRLEN);
343 gmx_getcwd(cpp->cwd, STRLEN);
344 if (nullptr != debug)
346 fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
348 gmx_chdir(cpp->path);
350 if (nullptr != debug)
352 fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
359 cpp->ifdefs = nullptr;
360 cpp->child = nullptr;
361 cpp->parent = nullptr;
362 if (cpp->fp == nullptr)
364 if (nullptr != debug)
366 fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
368 cpp->fp = fopen(cpp->fn, "r");
370 if (cpp->fp == nullptr)
383 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
385 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
386 int i, i0, len, status;
392 /* #ifdef or ifndef statement */
393 bIfdef = (strcmp(dname, "ifdef") == 0);
394 bIfndef = (strcmp(dname, "ifndef") == 0);
395 if (bIfdef || bIfndef)
397 GMX_RELEASE_ASSERT(dval, "#ifdef/#ifndef requires an argument");
398 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
401 srenew(handle->ifdefs, handle->nifdef);
402 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
406 snew(name, strlen(dval)+1);
407 sscanf(dval, "%s", name);
408 for (i = 0; (i < ndef); i++)
410 if (strcmp(defs[i].name, name) == 0)
416 srenew(handle->ifdefs, handle->nifdef);
417 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
419 handle->ifdefs[handle->nifdef-1] = eifTRUE;
423 handle->ifdefs[handle->nifdef-1] = eifFALSE;
430 /* #else statement */
431 if (strcmp(dname, "else") == 0)
433 if (handle->nifdef <= 0)
437 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
439 handle->ifdefs[handle->nifdef-1] = eifFALSE;
441 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
443 handle->ifdefs[handle->nifdef-1] = eifTRUE;
448 /* #endif statement */
449 if (strcmp(dname, "endif") == 0)
451 if (handle->nifdef <= 0)
459 /* Check whether we're not ifdeffed out. The order of this statement
460 is important. It has to come after #ifdef, #else and #endif, but
461 anything else should be ignored. */
462 if (is_ifdeffed_out(handle))
467 /* Check for include statements */
468 if (strcmp(dname, "include") == 0)
470 GMX_RELEASE_ASSERT(dval, "#include requires an argument");
473 for (i1 = 0; (i1 < strlen(dval)); i1++)
475 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
497 strncpy(inc_fn, dval+i0, len);
502 fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
505 /* Open include file and store it as a child in the handle structure */
506 status = cpp_open_file(inc_fn, &(handle->child), nullptr);
508 if (status != eCPP_OK)
510 handle->child = nullptr;
513 /* Make a linked list of open files and move on to the include file */
514 handle->child->parent = handle;
515 *handlep = handle->child;
519 /* #define statement */
520 if (strcmp(dname, "define") == 0)
522 GMX_RELEASE_ASSERT(dval, "#define requires an argument");
523 /* Split it into name and value. */
525 while ((*ptr != '\0') && !isspace(*ptr))
529 name = gmx_strndup(dval, ptr - dval);
531 while ((*ptr != '\0') && isspace(*ptr))
536 add_define(name, ptr);
541 /* #undef statement */
542 if (strcmp(dname, "undef") == 0)
544 GMX_RELEASE_ASSERT(dval, "#undef requires an argument");
545 snew(name, strlen(dval)+1);
546 sscanf(dval, "%s", name);
547 for (i = 0; (i < ndef); i++)
549 if (strcmp(defs[i].name, name) == 0)
557 for (; (i < ndef-1); i++)
559 defs[i].name = defs[i+1].name;
560 defs[i].def = defs[i+1].def;
567 /* If we haven't matched anything, this is an unknown directive */
571 /* Return one whole line from the file into buf which holds at most n
572 characters, for subsequent processing. Returns integer status. This
573 routine also does all the "intelligent" work like processing cpp
574 directives and so on. Note that often the routine is called
575 recursively and no cpp directives are printed. */
576 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
578 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
579 int i, nn, len, status;
580 const char *ptr, *ptr2;
587 return eCPP_INVALID_HANDLE;
591 return eCPP_FILE_NOT_OPEN;
594 bEOF = feof(handle->fp);
597 /* Read the actual line now. */
598 if (fgets2(buf, n-1, handle->fp) == nullptr)
600 /* Recheck EOF, since we could have been at the end before
601 * the fgets2 call, but we need to read past the end to know.
603 bEOF = feof(handle->fp);
606 /* Something strange happened, fgets returned NULL,
607 * but we are not at EOF.
616 if (handle->parent == nullptr)
620 cpp_close_file(handlep);
621 *handlep = handle->parent;
622 handle->child = nullptr;
623 return cpp_read_line(handlep, n, buf);
627 if (n > handle->line_len)
629 handle->line_len = n;
630 srenew(handle->line, n);
632 strcpy(handle->line, buf);
635 /* Now we've read a line! */
638 fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
641 /* Process directives if this line contains one */
642 if (find_directive(buf, &dname, &dval))
644 status = process_directive(handlep, dname, dval);
645 if (status != eCPP_OK)
649 /* Don't print lines with directives, go on to the next */
650 return cpp_read_line(handlep, n, buf);
653 /* Check whether we're not ifdeffed out. The order of this statement
654 is important. It has to come after #ifdef, #else and #endif, but
655 anything else should be ignored. */
656 if (is_ifdeffed_out(handle))
658 return cpp_read_line(handlep, n, buf);
661 /* Check whether we have any defines that need to be replaced. Note
662 that we have to use a best fit algorithm, rather than first come
663 first go. We do this by sorting the defines on length first, and
664 then on alphabetical order. */
665 for (i = 0; (i < ndef); i++)
671 while ((ptr = strstrw(ptr, defs[i].name)) != nullptr)
674 ptr += strlen(defs[i].name);
680 len = strlen(buf) + nn*std::max(four, four+strlen(defs[i].def)-strlen(defs[i].name));
683 while ((ptr2 = strstrw(ptr, defs[i].name)) != nullptr)
685 strncat(name, ptr, (int)(ptr2-ptr));
686 strcat(name, defs[i].def);
687 ptr = ptr2 + strlen(defs[i].name);
699 char *cpp_cur_file(const gmx_cpp_t *handlep)
701 return (*handlep)->fn;
704 int cpp_cur_linenr(const gmx_cpp_t *handlep)
706 return (*handlep)->line_nr;
709 /* Close the file! Return integer status. */
710 int cpp_close_file(gmx_cpp_t *handlep)
712 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
716 return eCPP_INVALID_HANDLE;
720 return eCPP_FILE_NOT_OPEN;
724 fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
727 if (nullptr != handle->cwd)
729 if (nullptr != debug)
731 fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
733 gmx_chdir(handle->cwd);
743 return eCPP_FILE_NOT_FOUND;
745 return eCPP_FILE_NOT_OPEN;
747 return eCPP_INTERRUPT;
751 fprintf(debug, "Strange stuff closing file, errno = %d", errno);
756 handle->fp = nullptr;
758 if (nullptr != handle->fn)
761 handle->fn = nullptr;
763 if (nullptr != handle->line)
766 handle->line = nullptr;
768 if (nullptr != handle->ifdefs)
770 sfree(handle->ifdefs);
773 if (nullptr != handle->path)
777 if (nullptr != handle->cwd)
791 /* Return a string containing the error message coresponding to status
793 char *cpp_error(gmx_cpp_t *handlep, int status)
796 const char *ecpp[] = {
797 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
798 "Invalid file handle",
799 "File not open", "Unknown error", "Error status out of range"
801 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
805 return (char *)ecpp[eCPP_INVALID_HANDLE];
808 if ((status < 0) || (status >= eCPP_NR))
813 sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
815 (handle && handle->fn) ? handle->fn : "unknown",
816 (handle) ? handle->line_nr : -1,
817 handle->line ? handle->line : "");
819 return gmx_strdup(buf);