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, 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/legacyheaders/macros.h"
55 #include "gromacs/utility/cstringutil.h"
56 #include "gromacs/utility/dir_separator.h"
57 #include "gromacs/utility/fatalerror.h"
58 #include "gromacs/utility/futil.h"
59 #include "gromacs/utility/smalloc.h"
67 static t_define *defs = NULL;
69 static char **incl = 0;
71 /* enum used for handling ifdefs */
73 eifTRUE, eifFALSE, eifIGNORE, eifNR
76 typedef struct gmx_cpp {
85 struct gmx_cpp *child, *parent;
88 static gmx_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)) != NULL)
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 gmx_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 : NULL;
151 static gmx_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)
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);
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, NULL);
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);
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 == NULL || (ptr2 != NULL && ptr2 > ptr))
340 cpp->fn = gmx_strdup(ptr+1);
341 snew(cpp->cwd, STRLEN);
343 gmx_getcwd(cpp->cwd, STRLEN);
346 fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
348 gmx_chdir(cpp->path);
352 fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
366 fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
368 cpp->fp = fopen(cpp->fn, "r");
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 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
400 srenew(handle->ifdefs, handle->nifdef);
401 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
405 snew(name, strlen(dval)+1);
406 sscanf(dval, "%s", name);
407 for (i = 0; (i < ndef); i++)
409 if (strcmp(defs[i].name, name) == 0)
415 srenew(handle->ifdefs, handle->nifdef);
416 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
418 handle->ifdefs[handle->nifdef-1] = eifTRUE;
422 handle->ifdefs[handle->nifdef-1] = eifFALSE;
429 /* #else statement */
430 if (strcmp(dname, "else") == 0)
432 if (handle->nifdef <= 0)
436 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
438 handle->ifdefs[handle->nifdef-1] = eifFALSE;
440 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
442 handle->ifdefs[handle->nifdef-1] = eifTRUE;
447 /* #endif statement */
448 if (strcmp(dname, "endif") == 0)
450 if (handle->nifdef <= 0)
458 /* Check whether we're not ifdeffed out. The order of this statement
459 is important. It has to come after #ifdef, #else and #endif, but
460 anything else should be ignored. */
461 if (is_ifdeffed_out(handle))
466 /* Check for include statements */
467 if (strcmp(dname, "include") == 0)
471 for (i1 = 0; (i1 < strlen(dval)); i1++)
473 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
495 strncpy(inc_fn, dval+i0, len);
500 fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
503 /* Open include file and store it as a child in the handle structure */
504 status = cpp_open_file(inc_fn, &(handle->child), NULL);
506 if (status != eCPP_OK)
508 handle->child = NULL;
511 /* Make a linked list of open files and move on to the include file */
512 handle->child->parent = handle;
513 *handlep = handle->child;
517 /* #define statement */
518 if (strcmp(dname, "define") == 0)
520 /* Split it into name and value. */
522 while ((*ptr != '\0') && !isspace(*ptr))
526 name = gmx_strndup(dval, ptr - dval);
528 while ((*ptr != '\0') && isspace(*ptr))
533 add_define(name, ptr);
538 /* #undef statement */
539 if (strcmp(dname, "undef") == 0)
541 snew(name, strlen(dval)+1);
542 sscanf(dval, "%s", name);
543 for (i = 0; (i < ndef); i++)
545 if (strcmp(defs[i].name, name) == 0)
553 for (; (i < ndef-1); i++)
555 defs[i].name = defs[i+1].name;
556 defs[i].def = defs[i+1].def;
563 /* If we haven't matched anything, this is an unknown directive */
567 /* Return one whole line from the file into buf which holds at most n
568 characters, for subsequent processing. Returns integer status. This
569 routine also does all the "intelligent" work like processing cpp
570 directives and so on. Note that often the routine is called
571 recursively and no cpp directives are printed. */
572 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
574 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
575 int i, nn, len, status;
576 const char *ptr, *ptr2;
583 return eCPP_INVALID_HANDLE;
587 return eCPP_FILE_NOT_OPEN;
590 bEOF = feof(handle->fp);
593 /* Read the actual line now. */
594 if (fgets2(buf, n-1, handle->fp) == NULL)
596 /* Recheck EOF, since we could have been at the end before
597 * the fgets2 call, but we need to read past the end to know.
599 bEOF = feof(handle->fp);
602 /* Something strange happened, fgets returned NULL,
603 * but we are not at EOF.
612 if (handle->parent == NULL)
616 cpp_close_file(handlep);
617 *handlep = handle->parent;
618 handle->child = NULL;
619 return cpp_read_line(handlep, n, buf);
623 if (n > handle->line_len)
625 handle->line_len = n;
626 srenew(handle->line, n);
628 strcpy(handle->line, buf);
631 /* Now we've read a line! */
634 fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
637 /* Process directives if this line contains one */
638 if (find_directive(buf, &dname, &dval))
640 status = process_directive(handlep, dname, dval);
641 if (status != eCPP_OK)
645 /* Don't print lines with directives, go on to the next */
646 return cpp_read_line(handlep, n, buf);
649 /* Check whether we're not ifdeffed out. The order of this statement
650 is important. It has to come after #ifdef, #else and #endif, but
651 anything else should be ignored. */
652 if (is_ifdeffed_out(handle))
654 return cpp_read_line(handlep, n, buf);
657 /* Check whether we have any defines that need to be replaced. Note
658 that we have to use a best fit algorithm, rather than first come
659 first go. We do this by sorting the defines on length first, and
660 then on alphabetical order. */
661 for (i = 0; (i < ndef); i++)
667 while ((ptr = strstrw(ptr, defs[i].name)) != NULL)
670 ptr += strlen(defs[i].name);
676 len = strlen(buf) + nn*std::max(four, four+strlen(defs[i].def)-strlen(defs[i].name));
679 while ((ptr2 = strstrw(ptr, defs[i].name)) != NULL)
681 strncat(name, ptr, (int)(ptr2-ptr));
682 strcat(name, defs[i].def);
683 ptr = ptr2 + strlen(defs[i].name);
695 char *cpp_cur_file(const gmx_cpp_t *handlep)
697 return (*handlep)->fn;
700 int cpp_cur_linenr(const gmx_cpp_t *handlep)
702 return (*handlep)->line_nr;
705 /* Close the file! Return integer status. */
706 int cpp_close_file(gmx_cpp_t *handlep)
708 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
712 return eCPP_INVALID_HANDLE;
716 return eCPP_FILE_NOT_OPEN;
720 fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
723 if (NULL != handle->cwd)
727 fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
729 gmx_chdir(handle->cwd);
739 return eCPP_FILE_NOT_FOUND;
741 return eCPP_FILE_NOT_OPEN;
743 return eCPP_INTERRUPT;
747 fprintf(debug, "Strange stuff closing file, errno = %d", errno);
754 if (NULL != handle->fn)
759 if (NULL != handle->line)
764 if (NULL != handle->ifdefs)
766 sfree(handle->ifdefs);
769 if (NULL != handle->path)
773 if (NULL != handle->cwd)
787 /* Return a string containing the error message coresponding to status
789 char *cpp_error(gmx_cpp_t *handlep, int status)
792 const char *ecpp[] = {
793 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
794 "Invalid file handle",
795 "File not open", "Unknown error", "Error status out of range"
797 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
801 return (char *)ecpp[eCPP_INVALID_HANDLE];
804 if ((status < 0) || (status >= eCPP_NR))
809 sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
811 (handle && handle->fn) ? handle->fn : "unknown",
812 (handle) ? handle->line_nr : -1,
813 handle->line ? handle->line : "");
815 return gmx_strdup(buf);