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.
49 #include <sys/types.h>
51 #include "gromacs/legacyheaders/macros.h"
52 #include "gromacs/utility/cstringutil.h"
53 #include "gromacs/utility/dir_separator.h"
54 #include "gromacs/utility/fatalerror.h"
55 #include "gromacs/utility/futil.h"
56 #include "gromacs/utility/smalloc.h"
64 static t_define *defs = NULL;
66 static char **incl = 0;
68 /* enum used for handling ifdefs */
70 eifTRUE, eifFALSE, eifIGNORE, eifNR
73 typedef struct gmx_cpp {
82 struct gmx_cpp *child, *parent;
85 static gmx_bool is_word_end(char c)
87 return !(isalnum(c) || c == '_');
90 static const char *strstrw(const char *buf, const char *word)
94 while ((ptr = strstr(buf, word)) != NULL)
96 /* Check if we did not find part of a longer word */
98 is_word_end(ptr[strlen(word)]) &&
99 (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
104 buf = ptr + strlen(word);
109 static gmx_bool find_directive(char *buf, char **name, char **val)
111 /* Skip initial whitespace */
112 while (isspace(*buf))
116 /* Check if this is a directive */
121 /* Skip the hash and any space after it */
123 while (isspace(*buf))
127 /* Set the name pointer and find the next space */
129 while (*buf != 0 && !isspace(*buf))
133 /* Set the end of the name here, and skip any space */
138 while (isspace(*buf))
143 /* Check if anything is remaining */
144 *val = (*buf != 0) ? buf : NULL;
148 static gmx_bool is_ifdeffed_out(gmx_cpp_t handle)
150 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
153 static void add_include(const char *include)
162 for (i = 0; (i < nincl); i++)
164 if (strcmp(incl[i], include) == 0)
173 incl[nincl-1] = gmx_strdup(include);
177 static void done_includes()
180 for (i = 0; (i < nincl); i++)
189 static void add_define(const char *name, const char *value)
193 for (i = 0; (i < ndef); i++)
195 if (strcmp(defs[i].name, name) == 0)
205 defs[i].name = gmx_strdup(name);
207 else if (defs[i].def)
211 fprintf(debug, "Overriding define %s\n", name);
215 if (value && strlen(value) > 0)
217 defs[i].def = gmx_strdup(value);
225 static void done_defines()
228 for (i = 0; (i < ndef); i++)
238 /* Open the file to be processed. The handle variable holds internal
239 info for the cpp emulator. Return integer status */
240 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
248 /* First process options, they might be necessary for opening files
249 (especially include statements). */
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], '=');
265 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
266 add_define(buf, ptr + 1);
271 add_define(cppopts[i] + 2, NULL);
279 fprintf(debug, "GMXCPP: added %d command line arguments\n", i);
285 /* Find the file. First check whether it is in the current directory. */
286 if (gmx_fexist(filenm))
288 cpp->fn = gmx_strdup(filenm);
292 /* If not, check all the paths given with -I. */
293 for (i = 0; i < nincl; ++i)
295 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
296 sprintf(buf, "%s/%s", incl[i], filenm);
304 /* If still not found, check the Gromacs library search path. */
307 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
312 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
316 fprintf(debug, "GMXCPP: cpp file open %s\n", cpp->fn);
318 /* If the file name has a path component, we need to change to that
319 * directory. Note that we - just as C - always use UNIX path separators
320 * internally in include file names.
322 ptr = strrchr(cpp->fn, '/');
323 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
325 if (ptr == NULL || (ptr2 != NULL && ptr2 > ptr))
338 cpp->fn = gmx_strdup(ptr+1);
339 snew(cpp->cwd, STRLEN);
341 gmx_getcwd(cpp->cwd, STRLEN);
344 fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
346 gmx_chdir(cpp->path);
350 fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
364 fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
366 cpp->fp = fopen(cpp->fn, "r");
381 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
383 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
384 int i, i0, len, status;
390 /* #ifdef or ifndef statement */
391 bIfdef = (strcmp(dname, "ifdef") == 0);
392 bIfndef = (strcmp(dname, "ifndef") == 0);
393 if (bIfdef || bIfndef)
395 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
398 srenew(handle->ifdefs, handle->nifdef);
399 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
403 snew(name, strlen(dval)+1);
404 sscanf(dval, "%s", name);
405 for (i = 0; (i < ndef); i++)
407 if (strcmp(defs[i].name, name) == 0)
413 srenew(handle->ifdefs, handle->nifdef);
414 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
416 handle->ifdefs[handle->nifdef-1] = eifTRUE;
420 handle->ifdefs[handle->nifdef-1] = eifFALSE;
427 /* #else statement */
428 if (strcmp(dname, "else") == 0)
430 if (handle->nifdef <= 0)
434 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
436 handle->ifdefs[handle->nifdef-1] = eifFALSE;
438 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
440 handle->ifdefs[handle->nifdef-1] = eifTRUE;
445 /* #endif statement */
446 if (strcmp(dname, "endif") == 0)
448 if (handle->nifdef <= 0)
456 /* Check whether we're not ifdeffed out. The order of this statement
457 is important. It has to come after #ifdef, #else and #endif, but
458 anything else should be ignored. */
459 if (is_ifdeffed_out(handle))
464 /* Check for include statements */
465 if (strcmp(dname, "include") == 0)
469 for (i1 = 0; (i1 < strlen(dval)); i1++)
471 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
493 strncpy(inc_fn, dval+i0, len);
498 fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
501 /* Open include file and store it as a child in the handle structure */
502 status = cpp_open_file(inc_fn, &(handle->child), NULL);
504 if (status != eCPP_OK)
506 handle->child = NULL;
509 /* Make a linked list of open files and move on to the include file */
510 handle->child->parent = handle;
511 *handlep = handle->child;
516 /* #define statement */
517 if (strcmp(dname, "define") == 0)
519 /* Split it into name and value. */
521 while ((*ptr != '\0') && !isspace(*ptr))
525 name = gmx_strndup(dval, ptr - dval);
527 while ((*ptr != '\0') && isspace(*ptr))
532 add_define(name, ptr);
537 /* #undef statement */
538 if (strcmp(dname, "undef") == 0)
540 snew(name, strlen(dval)+1);
541 sscanf(dval, "%s", name);
542 for (i = 0; (i < ndef); i++)
544 if (strcmp(defs[i].name, name) == 0)
552 for (; (i < ndef-1); i++)
554 defs[i].name = defs[i+1].name;
555 defs[i].def = defs[i+1].def;
562 /* If we haven't matched anything, this is an unknown directive */
566 /* Return one whole line from the file into buf which holds at most n
567 characters, for subsequent processing. Returns integer status. This
568 routine also does all the "intelligent" work like processing cpp
569 directives and so on. Note that often the routine is called
570 recursively and no cpp directives are printed. */
571 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
573 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
574 int i, nn, len, status;
575 const char *ptr, *ptr2;
582 return eCPP_INVALID_HANDLE;
586 return eCPP_FILE_NOT_OPEN;
589 bEOF = feof(handle->fp);
592 /* Read the actual line now. */
593 if (fgets2(buf, n-1, handle->fp) == NULL)
595 /* Recheck EOF, since we could have been at the end before
596 * the fgets2 call, but we need to read past the end to know.
598 bEOF = feof(handle->fp);
601 /* Something strange happened, fgets returned NULL,
602 * but we are not at EOF.
611 if (handle->parent == NULL)
615 cpp_close_file(handlep);
616 *handlep = handle->parent;
617 handle->child = NULL;
618 return cpp_read_line(handlep, n, buf);
622 if (n > handle->line_len)
624 handle->line_len = n;
625 srenew(handle->line, n);
627 strcpy(handle->line, buf);
630 /* Now we've read a line! */
633 fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
636 /* Process directives if this line contains one */
637 if (find_directive(buf, &dname, &dval))
639 status = process_directive(handlep, dname, dval);
640 if (status != eCPP_OK)
644 /* Don't print lines with directives, go on to the next */
645 return cpp_read_line(handlep, n, buf);
648 /* Check whether we're not ifdeffed out. The order of this statement
649 is important. It has to come after #ifdef, #else and #endif, but
650 anything else should be ignored. */
651 if (is_ifdeffed_out(handle))
653 return cpp_read_line(handlep, n, buf);
656 /* Check whether we have any defines that need to be replaced. Note
657 that we have to use a best fit algorithm, rather than first come
658 first go. We do this by sorting the defines on length first, and
659 then on alphabetical order. */
660 for (i = 0; (i < ndef); i++)
666 while ((ptr = strstrw(ptr, defs[i].name)) != NULL)
669 ptr += strlen(defs[i].name);
673 len = strlen(buf) + nn*max(4, 4+strlen(defs[i].def)-strlen(defs[i].name));
676 while ((ptr2 = strstrw(ptr, defs[i].name)) != NULL)
678 strncat(name, ptr, (int)(ptr2-ptr));
679 strcat(name, defs[i].def);
680 ptr = ptr2 + strlen(defs[i].name);
692 char *cpp_cur_file(const gmx_cpp_t *handlep)
694 return (*handlep)->fn;
697 int cpp_cur_linenr(const gmx_cpp_t *handlep)
699 return (*handlep)->line_nr;
702 /* Close the file! Return integer status. */
703 int cpp_close_file(gmx_cpp_t *handlep)
706 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
710 return eCPP_INVALID_HANDLE;
714 return eCPP_FILE_NOT_OPEN;
718 fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
721 if (NULL != handle->cwd)
725 fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
727 gmx_chdir(handle->cwd);
737 return eCPP_FILE_NOT_FOUND;
739 return eCPP_FILE_NOT_OPEN;
741 return eCPP_INTERRUPT;
745 fprintf(debug, "Strange stuff closing file, errno = %d", errno);
752 if (NULL != handle->fn)
757 if (NULL != handle->line)
762 if (NULL != handle->ifdefs)
764 sfree(handle->ifdefs);
767 if (NULL != handle->path)
771 if (NULL != handle->cwd)
785 /* Return a string containing the error message coresponding to status
787 char *cpp_error(gmx_cpp_t *handlep, int status)
790 const char *ecpp[] = {
791 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
792 "Invalid file handle",
793 "File not open", "Unknown error", "Error status out of range"
795 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
799 return (char *)ecpp[eCPP_INVALID_HANDLE];
802 if ((status < 0) || (status >= eCPP_NR))
807 sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
809 (handle && handle->fn) ? handle->fn : "unknown",
810 (handle) ? handle->line_nr : -1,
811 handle->line ? handle->line : "");
813 return gmx_strdup(buf);