3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
39 #include <sys/types.h>
48 /* Necessary for getcwd */
49 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
58 #include "gmx_fatal.h"
67 static t_define *defs = NULL;
69 static char **incl = 0;
71 /* enum used for handling ifdefs */
72 enum { eifTRUE, eifFALSE, eifIGNORE, eifNR };
74 typedef struct gmx_cpp {
83 struct gmx_cpp *child,*parent;
86 static gmx_bool is_word_end(char c)
88 return !(isalnum(c) || c == '_');
91 static const char *strstrw(const char *buf,const char *word)
95 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)))
102 buf = ptr + strlen(word);
107 static gmx_bool find_directive(char *buf, char **name, char **val)
109 /* Skip initial whitespace */
110 while (isspace(*buf)) ++buf;
111 /* Check if this is a directive */
114 /* Skip the hash and any space after it */
116 while (isspace(*buf)) ++buf;
117 /* Set the name pointer and find the next space */
119 while (*buf != 0 && !isspace(*buf)) ++buf;
120 /* Set the end of the name here, and skip any space */
125 while (isspace(*buf)) ++buf;
127 /* Check if anything is remaining */
128 *val = (*buf != 0) ? buf : NULL;
132 static gmx_bool is_ifdeffed_out(gmx_cpp_t handle)
134 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
137 static void add_include(const char *include)
144 for(i=0; (i<nincl); i++)
145 if (strcmp(incl[i],include) == 0)
150 incl[nincl-1] = strdup(include);
154 static void add_define(const char *name, const char *value)
158 for(i=0; (i<ndef); i++) {
159 if (strcmp(defs[i].name,name) == 0) {
167 defs[i].name = strdup(name);
169 else if (defs[i].def) {
171 fprintf(debug,"Overriding define %s\n",name);
174 if (value && strlen(value) > 0)
175 defs[i].def = strdup(value);
180 /* Open the file to be processed. The handle variable holds internal
181 info for the cpp emulator. Return integer status */
182 int cpp_open_file(const char *filenm,gmx_cpp_t *handle, char **cppopts)
190 /* First process options, they might be necessary for opening files
191 (especially include statements). */
195 if (strstr(cppopts[i],"-I") == cppopts[i])
196 add_include(cppopts[i]+2);
197 if (strstr(cppopts[i],"-D") == cppopts[i])
199 /* If the option contains a =, split it into name and value. */
200 ptr = strchr(cppopts[i], '=');
203 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
204 add_define(buf, ptr + 1);
209 add_define(cppopts[i] + 2, NULL);
216 fprintf(debug,"Added %d command line arguments",i);
221 /* Find the file. First check whether it is in the current directory. */
222 if (gmx_fexist(filenm))
224 cpp->fn = strdup(filenm);
228 /* If not, check all the paths given with -I. */
229 for (i = 0; i < nincl; ++i)
231 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
232 sprintf(buf, "%s%c%s", incl[i], DIR_SEPARATOR, filenm);
240 /* If still not found, check the Gromacs library search path. */
243 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
248 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
250 /* If the file name has a path component, we need to change to that
252 ptr = strrchr(cpp->fn, DIR_SEPARATOR);
262 cpp->fn = strdup(ptr+1);
263 snew(cpp->cwd,STRLEN);
265 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
266 pdum=_getcwd(cpp->cwd,STRLEN);
269 pdum=getcwd(cpp->cwd,STRLEN);
270 if (-1 == chdir(cpp->path))
271 gmx_fatal(FARGS,"Can not chdir to %s when processing topology. Reason: %s",
272 cpp->path,strerror(errno));
277 fprintf(debug,"GMXCPP: chdir to %s\n",cpp->path);
286 if (cpp->fp == NULL) {
287 cpp->fp = fopen(cpp->fn, "r");
289 if (cpp->fp == NULL) {
300 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
302 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
309 /* #ifdef or ifndef statement */
310 bIfdef = (strcmp(dname,"ifdef") == 0);
311 bIfndef = (strcmp(dname,"ifndef") == 0);
312 if (bIfdef || bIfndef) {
313 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE)) {
315 srenew(handle->ifdefs,handle->nifdef);
316 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
319 snew(name,strlen(dval)+1);
320 sscanf(dval,"%s",name);
321 for(i=0; (i<ndef); i++)
322 if (strcmp(defs[i].name,name) == 0)
325 srenew(handle->ifdefs,handle->nifdef);
326 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
327 handle->ifdefs[handle->nifdef-1] = eifTRUE;
329 handle->ifdefs[handle->nifdef-1] = eifFALSE;
335 /* #else statement */
336 if (strcmp(dname,"else") == 0) {
337 if (handle->nifdef <= 0)
339 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
340 handle->ifdefs[handle->nifdef-1] = eifFALSE;
341 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
342 handle->ifdefs[handle->nifdef-1] = eifTRUE;
346 /* #endif statement */
347 if (strcmp(dname,"endif") == 0) {
348 if (handle->nifdef <= 0)
354 /* Check whether we're not ifdeffed out. The order of this statement
355 is important. It has to come after #ifdef, #else and #endif, but
356 anything else should be ignored. */
357 if (is_ifdeffed_out(handle)) {
361 /* Check for include statements */
362 if (strcmp(dname,"include") == 0) {
365 for(i1=0; (i1<strlen(dval)); i1++) {
366 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>')) {
378 strncpy(inc_fn,dval+i0,len);
382 fprintf(debug,"Going to open include file '%s' i0 = %d, strlen = %d\n",
384 /* Open include file and store it as a child in the handle structure */
385 status = cpp_open_file(inc_fn,&(handle->child),NULL);
387 if (status != eCPP_OK) {
388 handle->child = NULL;
391 /* Make a linked list of open files and move on to the include file */
392 handle->child->parent = handle;
393 *handlep = handle->child;
398 /* #define statement */
399 if (strcmp(dname,"define") == 0) {
400 /* Split it into name and value. */
402 while ((*ptr != '\0') && !isspace(*ptr))
404 name = gmx_strndup(dval, ptr - dval);
406 while ((*ptr != '\0') && isspace(*ptr))
409 add_define(name, ptr);
414 /* #undef statement */
415 if (strcmp(dname,"undef") == 0) {
416 snew(name,strlen(dval)+1);
417 sscanf(dval,"%s",name);
418 for(i=0; (i<ndef); i++) {
419 if (strcmp(defs[i].name,name) == 0) {
426 for( ; (i<ndef-1); i++) {
427 defs[i].name = defs[i+1].name;
428 defs[i].def = defs[i+1].def;
435 /* If we haven't matched anything, this is an unknown directive */
439 /* Return one whole line from the file into buf which holds at most n
440 characters, for subsequent processing. Returns integer status. This
441 routine also does all the "intelligent" work like processing cpp
442 directives and so on. Note that often the routine is called
443 recursively and no cpp directives are printed. */
444 int cpp_read_line(gmx_cpp_t *handlep,int n,char buf[])
446 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
448 const char *ptr, *ptr2;
454 return eCPP_INVALID_HANDLE;
456 return eCPP_FILE_NOT_OPEN;
458 bEOF = feof(handle->fp);
460 /* Read the actual line now. */
461 if (fgets2(buf,n-1,handle->fp) == NULL) {
462 /* Recheck EOF, since we could have been at the end before
463 * the fgets2 call, but we need to read past the end to know.
465 bEOF = feof(handle->fp);
467 /* Something strange happened, fgets returned NULL,
468 * but we are not at EOF.
476 if (handle->parent == NULL) {
479 cpp_close_file(handlep);
480 *handlep = handle->parent;
481 handle->child = NULL;
482 return cpp_read_line(handlep,n,buf);
485 if (n > handle->line_len) {
486 handle->line_len = n;
487 srenew(handle->line,n);
489 strcpy(handle->line,buf);
492 /* Now we've read a line! */
494 fprintf(debug,"%s : %4d : %s\n",handle->fn,handle->line_nr,buf);
496 /* Process directives if this line contains one */
497 if (find_directive(buf, &dname, &dval))
499 status = process_directive(handlep, dname, dval);
500 if (status != eCPP_OK)
502 /* Don't print lines with directives, go on to the next */
503 return cpp_read_line(handlep,n,buf);
506 /* Check whether we're not ifdeffed out. The order of this statement
507 is important. It has to come after #ifdef, #else and #endif, but
508 anything else should be ignored. */
509 if (is_ifdeffed_out(handle)) {
510 return cpp_read_line(handlep,n,buf);
513 /* Check whether we have any defines that need to be replaced. Note
514 that we have to use a best fit algorithm, rather than first come
515 first go. We do this by sorting the defines on length first, and
516 then on alphabetical order. */
517 for(i=0; (i<ndef); i++) {
521 while ((ptr = strstrw(ptr,defs[i].name)) != NULL) {
523 ptr += strlen(defs[i].name);
526 len = strlen(buf) + nn*max(4,4+strlen(defs[i].def)-strlen(defs[i].name));
529 while ((ptr2 = strstrw(ptr,defs[i].name)) != NULL) {
530 strncat(name,ptr,(int)(ptr2-ptr));
531 strcat(name,defs[i].def);
532 ptr = ptr2 + strlen(defs[i].name);
544 char *cpp_cur_file(const gmx_cpp_t *handlep)
546 return (*handlep)->fn;
549 int cpp_cur_linenr(const gmx_cpp_t *handlep)
551 return (*handlep)->line_nr;
554 /* Close the file! Return integer status. */
555 int cpp_close_file(gmx_cpp_t *handlep)
558 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
561 return eCPP_INVALID_HANDLE;
563 return eCPP_FILE_NOT_OPEN;
565 fprintf(debug,"Closing file %s\n",handle->fn);
567 if (NULL != handle->cwd) {
569 fprintf(debug,"GMXCPP: chdir to %s\n",handle->cwd);
570 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
573 if (-1 == chdir(handle->cwd))
574 gmx_fatal(FARGS,"Can not chdir to %s when processing topology: %s",
575 handle->cwd,strerror(errno));
584 return eCPP_FILE_NOT_FOUND;
586 return eCPP_FILE_NOT_OPEN;
588 return eCPP_INTERRUPT;
591 fprintf(debug,"Strange stuff closing file, errno = %d",errno);
596 if (NULL != handle->fn) {
600 if (NULL != handle->line) {
604 if (NULL != handle->ifdefs)
605 sfree(handle->ifdefs);
607 if (NULL != handle->path)
609 if (NULL != handle->cwd)
615 /* Return a string containing the error message coresponding to status
617 char *cpp_error(gmx_cpp_t *handlep,int status)
620 const char *ecpp[] = {
621 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
622 "Invalid file handle",
623 "File not open", "Unknown error", "Error status out of range"
625 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
628 return (char *)ecpp[eCPP_INVALID_HANDLE];
630 if ((status < 0) || (status >= eCPP_NR))
633 sprintf(buf,"%s - File %s, line %d\nLast line read:\n'%s'",
635 (handle && handle->fn) ? handle->fn : "unknown",
636 (handle) ? handle->line_nr : -1,
637 handle->line ? handle->line : "");