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
38 #include "gmx_header_config.h"
40 #include <sys/types.h>
49 /* Necessary for getcwd */
50 #ifdef GMX_NATIVE_WINDOWS
59 #include "gmx_fatal.h"
68 static t_define *defs = NULL;
70 static char **incl = 0;
72 /* enum used for handling ifdefs */
73 enum { eifTRUE, eifFALSE, eifIGNORE, eifNR };
75 typedef struct gmx_cpp {
84 struct gmx_cpp *child,*parent;
87 static gmx_bool is_word_end(char c)
89 return !(isalnum(c) || c == '_');
92 static const char *strstrw(const char *buf,const char *word)
96 while ((ptr = strstr(buf,word)) != NULL) {
97 /* Check if we did not find part of a longer word */
99 is_word_end(ptr[strlen(word)]) &&
100 (((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)) ++buf;
112 /* Check if this is a directive */
115 /* Skip the hash and any space after it */
117 while (isspace(*buf)) ++buf;
118 /* Set the name pointer and find the next space */
120 while (*buf != 0 && !isspace(*buf)) ++buf;
121 /* Set the end of the name here, and skip any space */
126 while (isspace(*buf)) ++buf;
128 /* Check if anything is remaining */
129 *val = (*buf != 0) ? buf : NULL;
133 static gmx_bool is_ifdeffed_out(gmx_cpp_t handle)
135 return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
138 static void add_include(const char *include)
145 for(i=0; (i<nincl); i++)
146 if (strcmp(incl[i],include) == 0)
151 incl[nincl-1] = strdup(include);
155 static void add_define(const char *name, const char *value)
159 for(i=0; (i<ndef); i++) {
160 if (strcmp(defs[i].name,name) == 0) {
168 defs[i].name = strdup(name);
170 else if (defs[i].def) {
172 fprintf(debug,"Overriding define %s\n",name);
175 if (value && strlen(value) > 0)
176 defs[i].def = strdup(value);
181 /* Open the file to be processed. The handle variable holds internal
182 info for the cpp emulator. Return integer status */
183 int cpp_open_file(const char *filenm,gmx_cpp_t *handle, char **cppopts)
191 /* First process options, they might be necessary for opening files
192 (especially include statements). */
196 if (strstr(cppopts[i],"-I") == cppopts[i])
197 add_include(cppopts[i]+2);
198 if (strstr(cppopts[i],"-D") == cppopts[i])
200 /* If the option contains a =, split it into name and value. */
201 ptr = strchr(cppopts[i], '=');
204 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
205 add_define(buf, ptr + 1);
210 add_define(cppopts[i] + 2, NULL);
217 fprintf(debug,"GMXCPP: added %d command line arguments\n",i);
222 /* Find the file. First check whether it is in the current directory. */
223 if (gmx_fexist(filenm))
225 cpp->fn = strdup(filenm);
229 /* If not, check all the paths given with -I. */
230 for (i = 0; i < nincl; ++i)
232 snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
233 sprintf(buf, "%s/%s", incl[i], filenm);
241 /* If still not found, check the Gromacs library search path. */
244 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
249 gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
252 fprintf(debug,"GMXCPP: cpp file open %s\n",cpp->fn);
254 /* If the file name has a path component, we need to change to that
255 * directory. Note that we - just as C - always use UNIX path separators
256 * internally in include file names.
258 ptr = strrchr(cpp->fn, '/');
259 ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
261 if (ptr == NULL || (ptr2 != NULL && ptr2 > ptr))
274 cpp->fn = strdup(ptr+1);
275 snew(cpp->cwd,STRLEN);
277 #ifdef GMX_NATIVE_WINDOWS
278 pdum=_getcwd(cpp->cwd,STRLEN);
281 pdum=getcwd(cpp->cwd,STRLEN);
283 fprintf(debug,"GMXCPP: cwd %s\n",cpp->cwd);
285 if (-1 == chdir(cpp->path))
286 gmx_fatal(FARGS,"Can not chdir to %s when processing topology. Reason: %s",
287 cpp->path,strerror(errno));
292 fprintf(debug,"GMXCPP: chdir to %s\n",cpp->path);
301 if (cpp->fp == NULL) {
303 fprintf(debug,"GMXCPP: opening file %s\n",cpp->fn);
305 cpp->fp = fopen(cpp->fn, "r");
307 if (cpp->fp == NULL) {
318 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
320 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
327 /* #ifdef or ifndef statement */
328 bIfdef = (strcmp(dname,"ifdef") == 0);
329 bIfndef = (strcmp(dname,"ifndef") == 0);
330 if (bIfdef || bIfndef) {
331 if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE)) {
333 srenew(handle->ifdefs,handle->nifdef);
334 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
337 snew(name,strlen(dval)+1);
338 sscanf(dval,"%s",name);
339 for(i=0; (i<ndef); i++)
340 if (strcmp(defs[i].name,name) == 0)
343 srenew(handle->ifdefs,handle->nifdef);
344 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
345 handle->ifdefs[handle->nifdef-1] = eifTRUE;
347 handle->ifdefs[handle->nifdef-1] = eifFALSE;
353 /* #else statement */
354 if (strcmp(dname,"else") == 0) {
355 if (handle->nifdef <= 0)
357 if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
358 handle->ifdefs[handle->nifdef-1] = eifFALSE;
359 else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
360 handle->ifdefs[handle->nifdef-1] = eifTRUE;
364 /* #endif statement */
365 if (strcmp(dname,"endif") == 0) {
366 if (handle->nifdef <= 0)
372 /* Check whether we're not ifdeffed out. The order of this statement
373 is important. It has to come after #ifdef, #else and #endif, but
374 anything else should be ignored. */
375 if (is_ifdeffed_out(handle)) {
379 /* Check for include statements */
380 if (strcmp(dname,"include") == 0) {
383 for(i1=0; (i1<strlen(dval)); i1++) {
384 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>')) {
399 strncpy(inc_fn,dval+i0,len);
403 fprintf(debug,"Going to open include file '%s' i0 = %d, strlen = %d\n",
405 /* Open include file and store it as a child in the handle structure */
406 status = cpp_open_file(inc_fn,&(handle->child),NULL);
408 if (status != eCPP_OK) {
409 handle->child = NULL;
412 /* Make a linked list of open files and move on to the include file */
413 handle->child->parent = handle;
414 *handlep = handle->child;
419 /* #define statement */
420 if (strcmp(dname,"define") == 0) {
421 /* Split it into name and value. */
423 while ((*ptr != '\0') && !isspace(*ptr))
425 name = gmx_strndup(dval, ptr - dval);
427 while ((*ptr != '\0') && isspace(*ptr))
430 add_define(name, ptr);
435 /* #undef statement */
436 if (strcmp(dname,"undef") == 0) {
437 snew(name,strlen(dval)+1);
438 sscanf(dval,"%s",name);
439 for(i=0; (i<ndef); i++) {
440 if (strcmp(defs[i].name,name) == 0) {
447 for( ; (i<ndef-1); i++) {
448 defs[i].name = defs[i+1].name;
449 defs[i].def = defs[i+1].def;
456 /* If we haven't matched anything, this is an unknown directive */
460 /* Return one whole line from the file into buf which holds at most n
461 characters, for subsequent processing. Returns integer status. This
462 routine also does all the "intelligent" work like processing cpp
463 directives and so on. Note that often the routine is called
464 recursively and no cpp directives are printed. */
465 int cpp_read_line(gmx_cpp_t *handlep,int n,char buf[])
467 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
469 const char *ptr, *ptr2;
475 return eCPP_INVALID_HANDLE;
477 return eCPP_FILE_NOT_OPEN;
479 bEOF = feof(handle->fp);
481 /* Read the actual line now. */
482 if (fgets2(buf,n-1,handle->fp) == NULL) {
483 /* Recheck EOF, since we could have been at the end before
484 * the fgets2 call, but we need to read past the end to know.
486 bEOF = feof(handle->fp);
488 /* Something strange happened, fgets returned NULL,
489 * but we are not at EOF.
497 if (handle->parent == NULL) {
500 cpp_close_file(handlep);
501 *handlep = handle->parent;
502 handle->child = NULL;
503 return cpp_read_line(handlep,n,buf);
506 if (n > handle->line_len) {
507 handle->line_len = n;
508 srenew(handle->line,n);
510 strcpy(handle->line,buf);
513 /* Now we've read a line! */
515 fprintf(debug,"%s : %4d : %s\n",handle->fn,handle->line_nr,buf);
517 /* Process directives if this line contains one */
518 if (find_directive(buf, &dname, &dval))
520 status = process_directive(handlep, dname, dval);
521 if (status != eCPP_OK)
523 /* Don't print lines with directives, go on to the next */
524 return cpp_read_line(handlep,n,buf);
527 /* Check whether we're not ifdeffed out. The order of this statement
528 is important. It has to come after #ifdef, #else and #endif, but
529 anything else should be ignored. */
530 if (is_ifdeffed_out(handle)) {
531 return cpp_read_line(handlep,n,buf);
534 /* Check whether we have any defines that need to be replaced. Note
535 that we have to use a best fit algorithm, rather than first come
536 first go. We do this by sorting the defines on length first, and
537 then on alphabetical order. */
538 for(i=0; (i<ndef); i++) {
542 while ((ptr = strstrw(ptr,defs[i].name)) != NULL) {
544 ptr += strlen(defs[i].name);
547 len = strlen(buf) + nn*max(4,4+strlen(defs[i].def)-strlen(defs[i].name));
550 while ((ptr2 = strstrw(ptr,defs[i].name)) != NULL) {
551 strncat(name,ptr,(int)(ptr2-ptr));
552 strcat(name,defs[i].def);
553 ptr = ptr2 + strlen(defs[i].name);
565 char *cpp_cur_file(const gmx_cpp_t *handlep)
567 return (*handlep)->fn;
570 int cpp_cur_linenr(const gmx_cpp_t *handlep)
572 return (*handlep)->line_nr;
575 /* Close the file! Return integer status. */
576 int cpp_close_file(gmx_cpp_t *handlep)
579 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
582 return eCPP_INVALID_HANDLE;
584 return eCPP_FILE_NOT_OPEN;
586 fprintf(debug,"GMXCPP: closing file %s\n",handle->fn);
588 if (NULL != handle->cwd) {
590 fprintf(debug,"GMXCPP: chdir to %s\n",handle->cwd);
591 #ifdef GMX_NATIVE_WINDOWS
594 if (-1 == chdir(handle->cwd))
595 gmx_fatal(FARGS,"Can not chdir to %s when processing topology: %s",
596 handle->cwd,strerror(errno));
605 return eCPP_FILE_NOT_FOUND;
607 return eCPP_FILE_NOT_OPEN;
609 return eCPP_INTERRUPT;
612 fprintf(debug,"Strange stuff closing file, errno = %d",errno);
617 if (NULL != handle->fn) {
621 if (NULL != handle->line) {
625 if (NULL != handle->ifdefs)
626 sfree(handle->ifdefs);
628 if (NULL != handle->path)
630 if (NULL != handle->cwd)
636 /* Return a string containing the error message coresponding to status
638 char *cpp_error(gmx_cpp_t *handlep,int status)
641 const char *ecpp[] = {
642 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
643 "Invalid file handle",
644 "File not open", "Unknown error", "Error status out of range"
646 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
649 return (char *)ecpp[eCPP_INVALID_HANDLE];
651 if ((status < 0) || (status >= eCPP_NR))
654 sprintf(buf,"%s - File %s, line %d\nLast line read:\n'%s'",
656 (handle && handle->fn) ? handle->fn : "unknown",
657 (handle) ? handle->line_nr : -1,
658 handle->line ? handle->line : "");