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, 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.
39 #include <sys/types.h>
48 #include "gromacs/utility/cstringutil.h"
49 #include "gromacs/utility/smalloc.h"
50 #include "gromacs/utility/futil.h"
51 #include "gromacs/legacyheaders/macros.h"
52 #include "gromacs/utility/fatalerror.h"
61 static t_define *defs = NULL;
63 static char **incl = 0;
65 /* enum used for handling ifdefs */
67 eifTRUE, eifFALSE, eifIGNORE, eifNR
70 typedef struct gmx_cpp {
79 struct gmx_cpp *child, *parent;
82 static gmx_bool is_word_end(char c)
84 return !(isalnum(c) || c == '_');
87 static const char *strstrw(const char *buf, const char *word)
91 while ((ptr = strstr(buf, word)) != NULL)
93 /* Check if we did not find part of a longer word */
95 is_word_end(ptr[strlen(word)]) &&
96 (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
101 buf = ptr + strlen(word);
106 static gmx_bool find_directive(char *buf, char **name, char **val)
108 /* Skip initial whitespace */
109 while (isspace(*buf))
113 /* Check if this is a directive */
118 /* Skip the hash and any space after it */
120 while (isspace(*buf))
124 /* Set the name pointer and find the next space */
126 while (*buf != 0 && !isspace(*buf))
130 /* Set the end of the name here, and skip any space */
135 while (isspace(*buf))
140 /* Check if anything is remaining */
141 *val = (*buf != 0) ? buf : NULL;
145 static gmx_bool is_ifdeffed_out(gmx_cpp_t handle)
147 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
150 static void add_include(const char *include)
159 for (i = 0; (i < nincl); i++)
161 if (strcmp(incl[i], include) == 0)
170 incl[nincl-1] = gmx_strdup(include);
174 static void done_includes()
177 for (i = 0; (i < nincl); i++)
186 static void add_define(const char *name, const char *value)
190 for (i = 0; (i < ndef); i++)
192 if (strcmp(defs[i].name, name) == 0)
202 defs[i].name = gmx_strdup(name);
204 else if (defs[i].def)
208 fprintf(debug, "Overriding define %s\n", name);
212 if (value && strlen(value) > 0)
214 defs[i].def = gmx_strdup(value);
222 static void done_defines()
225 for (i = 0; (i < ndef); i++)
235 /* Open the file to be processed. The handle variable holds internal
236 info for the cpp emulator. Return integer status */
237 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
245 /* First process options, they might be necessary for opening files
246 (especially include statements). */
252 if (strstr(cppopts[i], "-I") == cppopts[i])
254 add_include(cppopts[i]+2);
256 if (strstr(cppopts[i], "-D") == cppopts[i])
258 /* If the option contains a =, split it into name and value. */
259 ptr = strchr(cppopts[i], '=');
262 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
263 add_define(buf, ptr + 1);
268 add_define(cppopts[i] + 2, NULL);
276 fprintf(debug, "GMXCPP: added %d command line arguments\n", i);
282 /* Find the file. First check whether it is in the current directory. */
283 if (gmx_fexist(filenm))
285 cpp->fn = gmx_strdup(filenm);
289 /* If not, check all the paths given with -I. */
290 for (i = 0; i < nincl; ++i)
292 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
293 sprintf(buf, "%s/%s", incl[i], filenm);
301 /* If still not found, check the Gromacs library search path. */
304 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
309 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
313 fprintf(debug, "GMXCPP: cpp file open %s\n", cpp->fn);
315 /* If the file name has a path component, we need to change to that
316 * directory. Note that we - just as C - always use UNIX path separators
317 * internally in include file names.
319 ptr = strrchr(cpp->fn, '/');
320 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
322 if (ptr == NULL || (ptr2 != NULL && ptr2 > ptr))
335 cpp->fn = gmx_strdup(ptr+1);
336 snew(cpp->cwd, STRLEN);
338 gmx_getcwd(cpp->cwd, STRLEN);
341 fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
343 gmx_chdir(cpp->path);
347 fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
361 fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
363 cpp->fp = fopen(cpp->fn, "r");
378 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
380 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
381 int i, i0, len, status;
387 /* #ifdef or ifndef statement */
388 bIfdef = (strcmp(dname, "ifdef") == 0);
389 bIfndef = (strcmp(dname, "ifndef") == 0);
390 if (bIfdef || bIfndef)
392 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
395 srenew(handle->ifdefs, handle->nifdef);
396 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
400 snew(name, strlen(dval)+1);
401 sscanf(dval, "%s", name);
402 for (i = 0; (i < ndef); i++)
404 if (strcmp(defs[i].name, name) == 0)
410 srenew(handle->ifdefs, handle->nifdef);
411 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
413 handle->ifdefs[handle->nifdef-1] = eifTRUE;
417 handle->ifdefs[handle->nifdef-1] = eifFALSE;
424 /* #else statement */
425 if (strcmp(dname, "else") == 0)
427 if (handle->nifdef <= 0)
431 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
433 handle->ifdefs[handle->nifdef-1] = eifFALSE;
435 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
437 handle->ifdefs[handle->nifdef-1] = eifTRUE;
442 /* #endif statement */
443 if (strcmp(dname, "endif") == 0)
445 if (handle->nifdef <= 0)
453 /* Check whether we're not ifdeffed out. The order of this statement
454 is important. It has to come after #ifdef, #else and #endif, but
455 anything else should be ignored. */
456 if (is_ifdeffed_out(handle))
461 /* Check for include statements */
462 if (strcmp(dname, "include") == 0)
466 for (i1 = 0; (i1 < strlen(dval)); i1++)
468 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
490 strncpy(inc_fn, dval+i0, len);
495 fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
498 /* Open include file and store it as a child in the handle structure */
499 status = cpp_open_file(inc_fn, &(handle->child), NULL);
501 if (status != eCPP_OK)
503 handle->child = NULL;
506 /* Make a linked list of open files and move on to the include file */
507 handle->child->parent = handle;
508 *handlep = handle->child;
513 /* #define statement */
514 if (strcmp(dname, "define") == 0)
516 /* Split it into name and value. */
518 while ((*ptr != '\0') && !isspace(*ptr))
522 name = gmx_strndup(dval, ptr - dval);
524 while ((*ptr != '\0') && isspace(*ptr))
529 add_define(name, ptr);
534 /* #undef statement */
535 if (strcmp(dname, "undef") == 0)
537 snew(name, strlen(dval)+1);
538 sscanf(dval, "%s", name);
539 for (i = 0; (i < ndef); i++)
541 if (strcmp(defs[i].name, name) == 0)
549 for (; (i < ndef-1); i++)
551 defs[i].name = defs[i+1].name;
552 defs[i].def = defs[i+1].def;
559 /* If we haven't matched anything, this is an unknown directive */
563 /* Return one whole line from the file into buf which holds at most n
564 characters, for subsequent processing. Returns integer status. This
565 routine also does all the "intelligent" work like processing cpp
566 directives and so on. Note that often the routine is called
567 recursively and no cpp directives are printed. */
568 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
570 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
571 int i, nn, len, status;
572 const char *ptr, *ptr2;
579 return eCPP_INVALID_HANDLE;
583 return eCPP_FILE_NOT_OPEN;
586 bEOF = feof(handle->fp);
589 /* Read the actual line now. */
590 if (fgets2(buf, n-1, handle->fp) == NULL)
592 /* Recheck EOF, since we could have been at the end before
593 * the fgets2 call, but we need to read past the end to know.
595 bEOF = feof(handle->fp);
598 /* Something strange happened, fgets returned NULL,
599 * but we are not at EOF.
608 if (handle->parent == NULL)
612 cpp_close_file(handlep);
613 *handlep = handle->parent;
614 handle->child = NULL;
615 return cpp_read_line(handlep, n, buf);
619 if (n > handle->line_len)
621 handle->line_len = n;
622 srenew(handle->line, n);
624 strcpy(handle->line, buf);
627 /* Now we've read a line! */
630 fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
633 /* Process directives if this line contains one */
634 if (find_directive(buf, &dname, &dval))
636 status = process_directive(handlep, dname, dval);
637 if (status != eCPP_OK)
641 /* Don't print lines with directives, go on to the next */
642 return cpp_read_line(handlep, n, buf);
645 /* Check whether we're not ifdeffed out. The order of this statement
646 is important. It has to come after #ifdef, #else and #endif, but
647 anything else should be ignored. */
648 if (is_ifdeffed_out(handle))
650 return cpp_read_line(handlep, n, buf);
653 /* Check whether we have any defines that need to be replaced. Note
654 that we have to use a best fit algorithm, rather than first come
655 first go. We do this by sorting the defines on length first, and
656 then on alphabetical order. */
657 for (i = 0; (i < ndef); i++)
663 while ((ptr = strstrw(ptr, defs[i].name)) != NULL)
666 ptr += strlen(defs[i].name);
670 len = strlen(buf) + nn*max(4, 4+strlen(defs[i].def)-strlen(defs[i].name));
673 while ((ptr2 = strstrw(ptr, defs[i].name)) != NULL)
675 strncat(name, ptr, (int)(ptr2-ptr));
676 strcat(name, defs[i].def);
677 ptr = ptr2 + strlen(defs[i].name);
689 char *cpp_cur_file(const gmx_cpp_t *handlep)
691 return (*handlep)->fn;
694 int cpp_cur_linenr(const gmx_cpp_t *handlep)
696 return (*handlep)->line_nr;
699 /* Close the file! Return integer status. */
700 int cpp_close_file(gmx_cpp_t *handlep)
703 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
707 return eCPP_INVALID_HANDLE;
711 return eCPP_FILE_NOT_OPEN;
715 fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
718 if (NULL != handle->cwd)
722 fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
724 gmx_chdir(handle->cwd);
734 return eCPP_FILE_NOT_FOUND;
736 return eCPP_FILE_NOT_OPEN;
738 return eCPP_INTERRUPT;
742 fprintf(debug, "Strange stuff closing file, errno = %d", errno);
749 if (NULL != handle->fn)
754 if (NULL != handle->line)
759 if (NULL != handle->ifdefs)
761 sfree(handle->ifdefs);
764 if (NULL != handle->path)
768 if (NULL != handle->cwd)
782 /* Return a string containing the error message coresponding to status
784 char *cpp_error(gmx_cpp_t *handlep, int status)
787 const char *ecpp[] = {
788 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
789 "Invalid file handle",
790 "File not open", "Unknown error", "Error status out of range"
792 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
796 return (char *)ecpp[eCPP_INVALID_HANDLE];
799 if ((status < 0) || (status >= eCPP_NR))
804 sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
806 (handle && handle->fn) ? handle->fn : "unknown",
807 (handle) ? handle->line_nr : -1,
808 handle->line ? handle->line : "");
810 return gmx_strdup(buf);