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
,"GMXCPP: added %d command line arguments\n",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/%s", incl
[i
], 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
);
251 fprintf(debug
,"GMXCPP: cpp file open %s\n",cpp
->fn
);
253 /* If the file name has a path component, we need to change to that
254 * directory. Note that we - just as C - always use UNIX path separators
255 * internally in include file names.
257 ptr
= strrchr(cpp
->fn
, '/');
258 ptr2
= strrchr(cpp
->fn
, DIR_SEPARATOR
);
260 if (ptr
== NULL
|| (ptr2
!= NULL
&& ptr2
> ptr
))
273 cpp
->fn
= strdup(ptr
+1);
274 snew(cpp
->cwd
,STRLEN
);
276 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
277 pdum
=_getcwd(cpp
->cwd
,STRLEN
);
280 pdum
=getcwd(cpp
->cwd
,STRLEN
);
282 fprintf(debug
,"GMXCPP: cwd %s\n",cpp
->cwd
);
284 if (-1 == chdir(cpp
->path
))
285 gmx_fatal(FARGS
,"Can not chdir to %s when processing topology. Reason: %s",
286 cpp
->path
,strerror(errno
));
291 fprintf(debug
,"GMXCPP: chdir to %s\n",cpp
->path
);
300 if (cpp
->fp
== NULL
) {
302 fprintf(debug
,"GMXCPP: opening file %s\n",cpp
->fn
);
304 cpp
->fp
= fopen(cpp
->fn
, "r");
306 if (cpp
->fp
== NULL
) {
317 process_directive(gmx_cpp_t
*handlep
, const char *dname
, const char *dval
)
319 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
326 /* #ifdef or ifndef statement */
327 bIfdef
= (strcmp(dname
,"ifdef") == 0);
328 bIfndef
= (strcmp(dname
,"ifndef") == 0);
329 if (bIfdef
|| bIfndef
) {
330 if ((handle
->nifdef
> 0) && (handle
->ifdefs
[handle
->nifdef
-1] != eifTRUE
)) {
332 srenew(handle
->ifdefs
,handle
->nifdef
);
333 handle
->ifdefs
[handle
->nifdef
-1] = eifIGNORE
;
336 snew(name
,strlen(dval
)+1);
337 sscanf(dval
,"%s",name
);
338 for(i
=0; (i
<ndef
); i
++)
339 if (strcmp(defs
[i
].name
,name
) == 0)
342 srenew(handle
->ifdefs
,handle
->nifdef
);
343 if ((bIfdef
&& (i
< ndef
)) || (bIfndef
&& (i
== ndef
)))
344 handle
->ifdefs
[handle
->nifdef
-1] = eifTRUE
;
346 handle
->ifdefs
[handle
->nifdef
-1] = eifFALSE
;
352 /* #else statement */
353 if (strcmp(dname
,"else") == 0) {
354 if (handle
->nifdef
<= 0)
356 if (handle
->ifdefs
[handle
->nifdef
-1] == eifTRUE
)
357 handle
->ifdefs
[handle
->nifdef
-1] = eifFALSE
;
358 else if (handle
->ifdefs
[handle
->nifdef
-1] == eifFALSE
)
359 handle
->ifdefs
[handle
->nifdef
-1] = eifTRUE
;
363 /* #endif statement */
364 if (strcmp(dname
,"endif") == 0) {
365 if (handle
->nifdef
<= 0)
371 /* Check whether we're not ifdeffed out. The order of this statement
372 is important. It has to come after #ifdef, #else and #endif, but
373 anything else should be ignored. */
374 if (is_ifdeffed_out(handle
)) {
378 /* Check for include statements */
379 if (strcmp(dname
,"include") == 0) {
382 for(i1
=0; (i1
<strlen(dval
)); i1
++) {
383 if ((dval
[i1
] == '"') || (dval
[i1
] == '<') || (dval
[i1
] == '>')) {
398 strncpy(inc_fn
,dval
+i0
,len
);
402 fprintf(debug
,"Going to open include file '%s' i0 = %d, strlen = %d\n",
404 /* Open include file and store it as a child in the handle structure */
405 status
= cpp_open_file(inc_fn
,&(handle
->child
),NULL
);
407 if (status
!= eCPP_OK
) {
408 handle
->child
= NULL
;
411 /* Make a linked list of open files and move on to the include file */
412 handle
->child
->parent
= handle
;
413 *handlep
= handle
->child
;
418 /* #define statement */
419 if (strcmp(dname
,"define") == 0) {
420 /* Split it into name and value. */
422 while ((*ptr
!= '\0') && !isspace(*ptr
))
424 name
= gmx_strndup(dval
, ptr
- dval
);
426 while ((*ptr
!= '\0') && isspace(*ptr
))
429 add_define(name
, ptr
);
434 /* #undef statement */
435 if (strcmp(dname
,"undef") == 0) {
436 snew(name
,strlen(dval
)+1);
437 sscanf(dval
,"%s",name
);
438 for(i
=0; (i
<ndef
); i
++) {
439 if (strcmp(defs
[i
].name
,name
) == 0) {
446 for( ; (i
<ndef
-1); i
++) {
447 defs
[i
].name
= defs
[i
+1].name
;
448 defs
[i
].def
= defs
[i
+1].def
;
455 /* If we haven't matched anything, this is an unknown directive */
459 /* Return one whole line from the file into buf which holds at most n
460 characters, for subsequent processing. Returns integer status. This
461 routine also does all the "intelligent" work like processing cpp
462 directives and so on. Note that often the routine is called
463 recursively and no cpp directives are printed. */
464 int cpp_read_line(gmx_cpp_t
*handlep
,int n
,char buf
[])
466 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
468 const char *ptr
, *ptr2
;
474 return eCPP_INVALID_HANDLE
;
476 return eCPP_FILE_NOT_OPEN
;
478 bEOF
= feof(handle
->fp
);
480 /* Read the actual line now. */
481 if (fgets2(buf
,n
-1,handle
->fp
) == NULL
) {
482 /* Recheck EOF, since we could have been at the end before
483 * the fgets2 call, but we need to read past the end to know.
485 bEOF
= feof(handle
->fp
);
487 /* Something strange happened, fgets returned NULL,
488 * but we are not at EOF.
496 if (handle
->parent
== NULL
) {
499 cpp_close_file(handlep
);
500 *handlep
= handle
->parent
;
501 handle
->child
= NULL
;
502 return cpp_read_line(handlep
,n
,buf
);
505 if (n
> handle
->line_len
) {
506 handle
->line_len
= n
;
507 srenew(handle
->line
,n
);
509 strcpy(handle
->line
,buf
);
512 /* Now we've read a line! */
514 fprintf(debug
,"%s : %4d : %s\n",handle
->fn
,handle
->line_nr
,buf
);
516 /* Process directives if this line contains one */
517 if (find_directive(buf
, &dname
, &dval
))
519 status
= process_directive(handlep
, dname
, dval
);
520 if (status
!= eCPP_OK
)
522 /* Don't print lines with directives, go on to the next */
523 return cpp_read_line(handlep
,n
,buf
);
526 /* Check whether we're not ifdeffed out. The order of this statement
527 is important. It has to come after #ifdef, #else and #endif, but
528 anything else should be ignored. */
529 if (is_ifdeffed_out(handle
)) {
530 return cpp_read_line(handlep
,n
,buf
);
533 /* Check whether we have any defines that need to be replaced. Note
534 that we have to use a best fit algorithm, rather than first come
535 first go. We do this by sorting the defines on length first, and
536 then on alphabetical order. */
537 for(i
=0; (i
<ndef
); i
++) {
541 while ((ptr
= strstrw(ptr
,defs
[i
].name
)) != NULL
) {
543 ptr
+= strlen(defs
[i
].name
);
546 len
= strlen(buf
) + nn
*max(4,4+strlen(defs
[i
].def
)-strlen(defs
[i
].name
));
549 while ((ptr2
= strstrw(ptr
,defs
[i
].name
)) != NULL
) {
550 strncat(name
,ptr
,(int)(ptr2
-ptr
));
551 strcat(name
,defs
[i
].def
);
552 ptr
= ptr2
+ strlen(defs
[i
].name
);
564 char *cpp_cur_file(const gmx_cpp_t
*handlep
)
566 return (*handlep
)->fn
;
569 int cpp_cur_linenr(const gmx_cpp_t
*handlep
)
571 return (*handlep
)->line_nr
;
574 /* Close the file! Return integer status. */
575 int cpp_close_file(gmx_cpp_t
*handlep
)
578 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
581 return eCPP_INVALID_HANDLE
;
583 return eCPP_FILE_NOT_OPEN
;
585 fprintf(debug
,"GMXCPP: closing file %s\n",handle
->fn
);
587 if (NULL
!= handle
->cwd
) {
589 fprintf(debug
,"GMXCPP: chdir to %s\n",handle
->cwd
);
590 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
593 if (-1 == chdir(handle
->cwd
))
594 gmx_fatal(FARGS
,"Can not chdir to %s when processing topology: %s",
595 handle
->cwd
,strerror(errno
));
604 return eCPP_FILE_NOT_FOUND
;
606 return eCPP_FILE_NOT_OPEN
;
608 return eCPP_INTERRUPT
;
611 fprintf(debug
,"Strange stuff closing file, errno = %d",errno
);
616 if (NULL
!= handle
->fn
) {
620 if (NULL
!= handle
->line
) {
624 if (NULL
!= handle
->ifdefs
)
625 sfree(handle
->ifdefs
);
627 if (NULL
!= handle
->path
)
629 if (NULL
!= handle
->cwd
)
635 /* Return a string containing the error message coresponding to status
637 char *cpp_error(gmx_cpp_t
*handlep
,int status
)
640 const char *ecpp
[] = {
641 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
642 "Invalid file handle",
643 "File not open", "Unknown error", "Error status out of range"
645 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
648 return (char *)ecpp
[eCPP_INVALID_HANDLE
];
650 if ((status
< 0) || (status
>= eCPP_NR
))
653 sprintf(buf
,"%s - File %s, line %d\nLast line read:\n'%s'",
655 (handle
&& handle
->fn
) ? handle
->fn
: "unknown",
656 (handle
) ? handle
->line_nr
: -1,
657 handle
->line
? handle
->line
: "");