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 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
41 #include "gmx_header_config.h"
43 #include <sys/types.h>
52 /* Necessary for getcwd */
53 #ifdef GMX_NATIVE_WINDOWS
62 #include "gmx_fatal.h"
71 static t_define *defs = NULL;
73 static char **incl = 0;
75 /* enum used for handling ifdefs */
76 enum { eifTRUE, eifFALSE, eifIGNORE, eifNR };
78 typedef struct gmx_cpp {
87 struct gmx_cpp *child,*parent;
90 static gmx_bool is_word_end(char c)
92 return !(isalnum(c) || c == '_');
95 static const char *strstrw(const char *buf,const char *word)
99 while ((ptr = strstr(buf,word)) != NULL) {
100 /* Check if we did not find part of a longer word */
102 is_word_end(ptr[strlen(word)]) &&
103 (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
106 buf = ptr + strlen(word);
111 static gmx_bool find_directive(char *buf, char **name, char **val)
113 /* Skip initial whitespace */
114 while (isspace(*buf)) ++buf;
115 /* Check if this is a directive */
118 /* Skip the hash and any space after it */
120 while (isspace(*buf)) ++buf;
121 /* Set the name pointer and find the next space */
123 while (*buf != 0 && !isspace(*buf)) ++buf;
124 /* Set the end of the name here, and skip any space */
129 while (isspace(*buf)) ++buf;
131 /* Check if anything is remaining */
132 *val = (*buf != 0) ? buf : NULL;
136 static gmx_bool is_ifdeffed_out(gmx_cpp_t handle)
138 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
141 static void add_include(const char *include)
148 for(i=0; (i<nincl); i++)
149 if (strcmp(incl[i],include) == 0)
154 incl[nincl-1] = strdup(include);
158 static void add_define(const char *name, const char *value)
162 for(i=0; (i<ndef); i++) {
163 if (strcmp(defs[i].name,name) == 0) {
171 defs[i].name = strdup(name);
173 else if (defs[i].def) {
175 fprintf(debug,"Overriding define %s\n",name);
178 if (value && strlen(value) > 0)
179 defs[i].def = strdup(value);
184 /* Open the file to be processed. The handle variable holds internal
185 info for the cpp emulator. Return integer status */
186 int cpp_open_file(const char *filenm,gmx_cpp_t *handle, char **cppopts)
194 /* First process options, they might be necessary for opening files
195 (especially include statements). */
199 if (strstr(cppopts[i],"-I") == cppopts[i])
200 add_include(cppopts[i]+2);
201 if (strstr(cppopts[i],"-D") == cppopts[i])
203 /* If the option contains a =, split it into name and value. */
204 ptr = strchr(cppopts[i], '=');
207 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
208 add_define(buf, ptr + 1);
213 add_define(cppopts[i] + 2, NULL);
220 fprintf(debug,"GMXCPP: added %d command line arguments\n",i);
225 /* Find the file. First check whether it is in the current directory. */
226 if (gmx_fexist(filenm))
228 cpp->fn = strdup(filenm);
232 /* If not, check all the paths given with -I. */
233 for (i = 0; i < nincl; ++i)
235 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
236 sprintf(buf, "%s/%s", incl[i], filenm);
244 /* If still not found, check the Gromacs library search path. */
247 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
252 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
255 fprintf(debug,"GMXCPP: cpp file open %s\n",cpp->fn);
257 /* If the file name has a path component, we need to change to that
258 * directory. Note that we - just as C - always use UNIX path separators
259 * internally in include file names.
261 ptr = strrchr(cpp->fn, '/');
262 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
264 if (ptr == NULL || (ptr2 != NULL && ptr2 > ptr))
277 cpp->fn = strdup(ptr+1);
278 snew(cpp->cwd,STRLEN);
280 #ifdef GMX_NATIVE_WINDOWS
281 pdum=_getcwd(cpp->cwd,STRLEN);
284 pdum=getcwd(cpp->cwd,STRLEN);
286 fprintf(debug,"GMXCPP: cwd %s\n",cpp->cwd);
288 if (-1 == chdir(cpp->path))
289 gmx_fatal(FARGS,"Can not chdir to %s when processing topology. Reason: %s",
290 cpp->path,strerror(errno));
295 fprintf(debug,"GMXCPP: chdir to %s\n",cpp->path);
304 if (cpp->fp == NULL) {
306 fprintf(debug,"GMXCPP: opening file %s\n",cpp->fn);
308 cpp->fp = fopen(cpp->fn, "r");
310 if (cpp->fp == NULL) {
321 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
323 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
330 /* #ifdef or ifndef statement */
331 bIfdef = (strcmp(dname,"ifdef") == 0);
332 bIfndef = (strcmp(dname,"ifndef") == 0);
333 if (bIfdef || bIfndef) {
334 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE)) {
336 srenew(handle->ifdefs,handle->nifdef);
337 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
340 snew(name,strlen(dval)+1);
341 sscanf(dval,"%s",name);
342 for(i=0; (i<ndef); i++)
343 if (strcmp(defs[i].name,name) == 0)
346 srenew(handle->ifdefs,handle->nifdef);
347 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
348 handle->ifdefs[handle->nifdef-1] = eifTRUE;
350 handle->ifdefs[handle->nifdef-1] = eifFALSE;
356 /* #else statement */
357 if (strcmp(dname,"else") == 0) {
358 if (handle->nifdef <= 0)
360 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
361 handle->ifdefs[handle->nifdef-1] = eifFALSE;
362 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
363 handle->ifdefs[handle->nifdef-1] = eifTRUE;
367 /* #endif statement */
368 if (strcmp(dname,"endif") == 0) {
369 if (handle->nifdef <= 0)
375 /* Check whether we're not ifdeffed out. The order of this statement
376 is important. It has to come after #ifdef, #else and #endif, but
377 anything else should be ignored. */
378 if (is_ifdeffed_out(handle)) {
382 /* Check for include statements */
383 if (strcmp(dname,"include") == 0) {
386 for(i1=0; (i1<strlen(dval)); i1++) {
387 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>')) {
402 strncpy(inc_fn,dval+i0,len);
406 fprintf(debug,"Going to open include file '%s' i0 = %d, strlen = %d\n",
408 /* Open include file and store it as a child in the handle structure */
409 status = cpp_open_file(inc_fn,&(handle->child),NULL);
411 if (status != eCPP_OK) {
412 handle->child = NULL;
415 /* Make a linked list of open files and move on to the include file */
416 handle->child->parent = handle;
417 *handlep = handle->child;
422 /* #define statement */
423 if (strcmp(dname,"define") == 0) {
424 /* Split it into name and value. */
426 while ((*ptr != '\0') && !isspace(*ptr))
428 name = gmx_strndup(dval, ptr - dval);
430 while ((*ptr != '\0') && isspace(*ptr))
433 add_define(name, ptr);
438 /* #undef statement */
439 if (strcmp(dname,"undef") == 0) {
440 snew(name,strlen(dval)+1);
441 sscanf(dval,"%s",name);
442 for(i=0; (i<ndef); i++) {
443 if (strcmp(defs[i].name,name) == 0) {
450 for( ; (i<ndef-1); i++) {
451 defs[i].name = defs[i+1].name;
452 defs[i].def = defs[i+1].def;
459 /* If we haven't matched anything, this is an unknown directive */
463 /* Return one whole line from the file into buf which holds at most n
464 characters, for subsequent processing. Returns integer status. This
465 routine also does all the "intelligent" work like processing cpp
466 directives and so on. Note that often the routine is called
467 recursively and no cpp directives are printed. */
468 int cpp_read_line(gmx_cpp_t *handlep,int n,char buf[])
470 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
472 const char *ptr, *ptr2;
478 return eCPP_INVALID_HANDLE;
480 return eCPP_FILE_NOT_OPEN;
482 bEOF = feof(handle->fp);
484 /* Read the actual line now. */
485 if (fgets2(buf,n-1,handle->fp) == NULL) {
486 /* Recheck EOF, since we could have been at the end before
487 * the fgets2 call, but we need to read past the end to know.
489 bEOF = feof(handle->fp);
491 /* Something strange happened, fgets returned NULL,
492 * but we are not at EOF.
500 if (handle->parent == NULL) {
503 cpp_close_file(handlep);
504 *handlep = handle->parent;
505 handle->child = NULL;
506 return cpp_read_line(handlep,n,buf);
509 if (n > handle->line_len) {
510 handle->line_len = n;
511 srenew(handle->line,n);
513 strcpy(handle->line,buf);
516 /* Now we've read a line! */
518 fprintf(debug,"%s : %4d : %s\n",handle->fn,handle->line_nr,buf);
520 /* Process directives if this line contains one */
521 if (find_directive(buf, &dname, &dval))
523 status = process_directive(handlep, dname, dval);
524 if (status != eCPP_OK)
526 /* Don't print lines with directives, go on to the next */
527 return cpp_read_line(handlep,n,buf);
530 /* Check whether we're not ifdeffed out. The order of this statement
531 is important. It has to come after #ifdef, #else and #endif, but
532 anything else should be ignored. */
533 if (is_ifdeffed_out(handle)) {
534 return cpp_read_line(handlep,n,buf);
537 /* Check whether we have any defines that need to be replaced. Note
538 that we have to use a best fit algorithm, rather than first come
539 first go. We do this by sorting the defines on length first, and
540 then on alphabetical order. */
541 for(i=0; (i<ndef); i++) {
545 while ((ptr = strstrw(ptr,defs[i].name)) != NULL) {
547 ptr += strlen(defs[i].name);
550 len = strlen(buf) + nn*max(4,4+strlen(defs[i].def)-strlen(defs[i].name));
553 while ((ptr2 = strstrw(ptr,defs[i].name)) != NULL) {
554 strncat(name,ptr,(int)(ptr2-ptr));
555 strcat(name,defs[i].def);
556 ptr = ptr2 + strlen(defs[i].name);
568 char *cpp_cur_file(const gmx_cpp_t *handlep)
570 return (*handlep)->fn;
573 int cpp_cur_linenr(const gmx_cpp_t *handlep)
575 return (*handlep)->line_nr;
578 /* Close the file! Return integer status. */
579 int cpp_close_file(gmx_cpp_t *handlep)
582 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
585 return eCPP_INVALID_HANDLE;
587 return eCPP_FILE_NOT_OPEN;
589 fprintf(debug,"GMXCPP: closing file %s\n",handle->fn);
591 if (NULL != handle->cwd) {
593 fprintf(debug,"GMXCPP: chdir to %s\n",handle->cwd);
594 #ifdef GMX_NATIVE_WINDOWS
597 if (-1 == chdir(handle->cwd))
598 gmx_fatal(FARGS,"Can not chdir to %s when processing topology: %s",
599 handle->cwd,strerror(errno));
608 return eCPP_FILE_NOT_FOUND;
610 return eCPP_FILE_NOT_OPEN;
612 return eCPP_INTERRUPT;
615 fprintf(debug,"Strange stuff closing file, errno = %d",errno);
620 if (NULL != handle->fn) {
624 if (NULL != handle->line) {
628 if (NULL != handle->ifdefs)
629 sfree(handle->ifdefs);
631 if (NULL != handle->path)
633 if (NULL != handle->cwd)
639 /* Return a string containing the error message coresponding to status
641 char *cpp_error(gmx_cpp_t *handlep,int status)
644 const char *ecpp[] = {
645 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
646 "Invalid file handle",
647 "File not open", "Unknown error", "Error status out of range"
649 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
652 return (char *)ecpp[eCPP_INVALID_HANDLE];
654 if ((status < 0) || (status >= eCPP_NR))
657 sprintf(buf,"%s - File %s, line %d\nLast line read:\n'%s'",
659 (handle && handle->fn) ? handle->fn : "unknown",
660 (handle) ? handle->line_nr : -1,
661 handle->line ? handle->line : "");