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, 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.
41 #include <sys/types.h>
52 #include "gromacs/fileio/futil.h"
54 #include "gmx_fatal.h"
63 static t_define *defs = NULL;
65 static char **incl = 0;
67 /* enum used for handling ifdefs */
69 eifTRUE, eifFALSE, eifIGNORE, eifNR
72 typedef struct gmx_cpp {
81 struct gmx_cpp *child, *parent;
84 static gmx_bool is_word_end(char c)
86 return !(isalnum(c) || c == '_');
89 static const char *strstrw(const char *buf, const char *word)
93 while ((ptr = strstr(buf, word)) != NULL)
95 /* Check if we did not find part of a longer word */
97 is_word_end(ptr[strlen(word)]) &&
98 (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
103 buf = ptr + strlen(word);
108 static gmx_bool find_directive(char *buf, char **name, char **val)
110 /* Skip initial whitespace */
111 while (isspace(*buf))
115 /* Check if this is a directive */
120 /* Skip the hash and any space after it */
122 while (isspace(*buf))
126 /* Set the name pointer and find the next space */
128 while (*buf != 0 && !isspace(*buf))
132 /* Set the end of the name here, and skip any space */
137 while (isspace(*buf))
142 /* Check if anything is remaining */
143 *val = (*buf != 0) ? buf : NULL;
147 static gmx_bool is_ifdeffed_out(gmx_cpp_t handle)
149 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
152 static void add_include(const char *include)
161 for (i = 0; (i < nincl); i++)
163 if (strcmp(incl[i], include) == 0)
172 incl[nincl-1] = strdup(include);
176 static void add_define(const char *name, const char *value)
180 for (i = 0; (i < ndef); i++)
182 if (strcmp(defs[i].name, name) == 0)
192 defs[i].name = strdup(name);
194 else if (defs[i].def)
198 fprintf(debug, "Overriding define %s\n", name);
202 if (value && strlen(value) > 0)
204 defs[i].def = strdup(value);
212 /* Open the file to be processed. The handle variable holds internal
213 info for the cpp emulator. Return integer status */
214 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
222 /* First process options, they might be necessary for opening files
223 (especially include statements). */
229 if (strstr(cppopts[i], "-I") == cppopts[i])
231 add_include(cppopts[i]+2);
233 if (strstr(cppopts[i], "-D") == cppopts[i])
235 /* If the option contains a =, split it into name and value. */
236 ptr = strchr(cppopts[i], '=');
239 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
240 add_define(buf, ptr + 1);
245 add_define(cppopts[i] + 2, NULL);
253 fprintf(debug, "GMXCPP: added %d command line arguments\n", i);
259 /* Find the file. First check whether it is in the current directory. */
260 if (gmx_fexist(filenm))
262 cpp->fn = strdup(filenm);
266 /* If not, check all the paths given with -I. */
267 for (i = 0; i < nincl; ++i)
269 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
270 sprintf(buf, "%s/%s", incl[i], filenm);
278 /* If still not found, check the Gromacs library search path. */
281 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
286 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
290 fprintf(debug, "GMXCPP: cpp file open %s\n", cpp->fn);
292 /* If the file name has a path component, we need to change to that
293 * directory. Note that we - just as C - always use UNIX path separators
294 * internally in include file names.
296 ptr = strrchr(cpp->fn, '/');
297 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
299 if (ptr == NULL || (ptr2 != NULL && ptr2 > ptr))
312 cpp->fn = strdup(ptr+1);
313 snew(cpp->cwd, STRLEN);
315 gmx_getcwd(cpp->cwd, STRLEN);
318 fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
320 gmx_chdir(cpp->path);
324 fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
338 fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
340 cpp->fp = fopen(cpp->fn, "r");
355 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
357 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
358 int i, i0, len, status;
364 /* #ifdef or ifndef statement */
365 bIfdef = (strcmp(dname, "ifdef") == 0);
366 bIfndef = (strcmp(dname, "ifndef") == 0);
367 if (bIfdef || bIfndef)
369 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
372 srenew(handle->ifdefs, handle->nifdef);
373 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
377 snew(name, strlen(dval)+1);
378 sscanf(dval, "%s", name);
379 for (i = 0; (i < ndef); i++)
381 if (strcmp(defs[i].name, name) == 0)
387 srenew(handle->ifdefs, handle->nifdef);
388 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
390 handle->ifdefs[handle->nifdef-1] = eifTRUE;
394 handle->ifdefs[handle->nifdef-1] = eifFALSE;
401 /* #else statement */
402 if (strcmp(dname, "else") == 0)
404 if (handle->nifdef <= 0)
408 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
410 handle->ifdefs[handle->nifdef-1] = eifFALSE;
412 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
414 handle->ifdefs[handle->nifdef-1] = eifTRUE;
419 /* #endif statement */
420 if (strcmp(dname, "endif") == 0)
422 if (handle->nifdef <= 0)
430 /* Check whether we're not ifdeffed out. The order of this statement
431 is important. It has to come after #ifdef, #else and #endif, but
432 anything else should be ignored. */
433 if (is_ifdeffed_out(handle))
438 /* Check for include statements */
439 if (strcmp(dname, "include") == 0)
443 for (i1 = 0; (i1 < strlen(dval)); i1++)
445 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
467 strncpy(inc_fn, dval+i0, len);
472 fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
475 /* Open include file and store it as a child in the handle structure */
476 status = cpp_open_file(inc_fn, &(handle->child), NULL);
478 if (status != eCPP_OK)
480 handle->child = NULL;
483 /* Make a linked list of open files and move on to the include file */
484 handle->child->parent = handle;
485 *handlep = handle->child;
490 /* #define statement */
491 if (strcmp(dname, "define") == 0)
493 /* Split it into name and value. */
495 while ((*ptr != '\0') && !isspace(*ptr))
499 name = gmx_strndup(dval, ptr - dval);
501 while ((*ptr != '\0') && isspace(*ptr))
506 add_define(name, ptr);
511 /* #undef statement */
512 if (strcmp(dname, "undef") == 0)
514 snew(name, strlen(dval)+1);
515 sscanf(dval, "%s", name);
516 for (i = 0; (i < ndef); i++)
518 if (strcmp(defs[i].name, name) == 0)
526 for (; (i < ndef-1); i++)
528 defs[i].name = defs[i+1].name;
529 defs[i].def = defs[i+1].def;
536 /* If we haven't matched anything, this is an unknown directive */
540 /* Return one whole line from the file into buf which holds at most n
541 characters, for subsequent processing. Returns integer status. This
542 routine also does all the "intelligent" work like processing cpp
543 directives and so on. Note that often the routine is called
544 recursively and no cpp directives are printed. */
545 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
547 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
548 int i, nn, len, status;
549 const char *ptr, *ptr2;
556 return eCPP_INVALID_HANDLE;
560 return eCPP_FILE_NOT_OPEN;
563 bEOF = feof(handle->fp);
566 /* Read the actual line now. */
567 if (fgets2(buf, n-1, handle->fp) == NULL)
569 /* Recheck EOF, since we could have been at the end before
570 * the fgets2 call, but we need to read past the end to know.
572 bEOF = feof(handle->fp);
575 /* Something strange happened, fgets returned NULL,
576 * but we are not at EOF.
585 if (handle->parent == NULL)
589 cpp_close_file(handlep);
590 *handlep = handle->parent;
591 handle->child = NULL;
592 return cpp_read_line(handlep, n, buf);
596 if (n > handle->line_len)
598 handle->line_len = n;
599 srenew(handle->line, n);
601 strcpy(handle->line, buf);
604 /* Now we've read a line! */
607 fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
610 /* Process directives if this line contains one */
611 if (find_directive(buf, &dname, &dval))
613 status = process_directive(handlep, dname, dval);
614 if (status != eCPP_OK)
618 /* Don't print lines with directives, go on to the next */
619 return cpp_read_line(handlep, n, buf);
622 /* Check whether we're not ifdeffed out. The order of this statement
623 is important. It has to come after #ifdef, #else and #endif, but
624 anything else should be ignored. */
625 if (is_ifdeffed_out(handle))
627 return cpp_read_line(handlep, n, buf);
630 /* Check whether we have any defines that need to be replaced. Note
631 that we have to use a best fit algorithm, rather than first come
632 first go. We do this by sorting the defines on length first, and
633 then on alphabetical order. */
634 for (i = 0; (i < ndef); i++)
640 while ((ptr = strstrw(ptr, defs[i].name)) != NULL)
643 ptr += strlen(defs[i].name);
647 len = strlen(buf) + nn*max(4, 4+strlen(defs[i].def)-strlen(defs[i].name));
650 while ((ptr2 = strstrw(ptr, defs[i].name)) != NULL)
652 strncat(name, ptr, (int)(ptr2-ptr));
653 strcat(name, defs[i].def);
654 ptr = ptr2 + strlen(defs[i].name);
666 char *cpp_cur_file(const gmx_cpp_t *handlep)
668 return (*handlep)->fn;
671 int cpp_cur_linenr(const gmx_cpp_t *handlep)
673 return (*handlep)->line_nr;
676 /* Close the file! Return integer status. */
677 int cpp_close_file(gmx_cpp_t *handlep)
680 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
684 return eCPP_INVALID_HANDLE;
688 return eCPP_FILE_NOT_OPEN;
692 fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
695 if (NULL != handle->cwd)
699 fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
701 gmx_chdir(handle->cwd);
711 return eCPP_FILE_NOT_FOUND;
713 return eCPP_FILE_NOT_OPEN;
715 return eCPP_INTERRUPT;
719 fprintf(debug, "Strange stuff closing file, errno = %d", errno);
726 if (NULL != handle->fn)
731 if (NULL != handle->line)
736 if (NULL != handle->ifdefs)
738 sfree(handle->ifdefs);
741 if (NULL != handle->path)
745 if (NULL != handle->cwd)
753 /* Return a string containing the error message coresponding to status
755 char *cpp_error(gmx_cpp_t *handlep, int status)
758 const char *ecpp[] = {
759 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
760 "Invalid file handle",
761 "File not open", "Unknown error", "Error status out of range"
763 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
767 return (char *)ecpp[eCPP_INVALID_HANDLE];
770 if ((status < 0) || (status >= eCPP_NR))
775 sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
777 (handle && handle->fn) ? handle->fn : "unknown",
778 (handle) ? handle->line_nr : -1,
779 handle->line ? handle->line : "");