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/%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
);
250 /* If the file name has a path component, we need to change to that
251 * directory. Note that we - just as C - always use UNIX path separators
252 * internally in include file names.
254 ptr
= strrchr(cpp
->fn
, '/');
255 ptr2
= strrchr(cpp
->fn
, DIR_SEPARATOR
);
257 if (ptr
== NULL
|| (ptr2
!= NULL
&& ptr2
> ptr
))
270 cpp
->fn
= strdup(ptr
+1);
271 snew(cpp
->cwd
,STRLEN
);
273 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
274 pdum
=_getcwd(cpp
->cwd
,STRLEN
);
277 pdum
=getcwd(cpp
->cwd
,STRLEN
);
278 if (-1 == chdir(cpp
->path
))
279 gmx_fatal(FARGS
,"Can not chdir to %s when processing topology. Reason: %s",
280 cpp
->path
,strerror(errno
));
285 fprintf(debug
,"GMXCPP: chdir to %s\n",cpp
->path
);
294 if (cpp
->fp
== NULL
) {
295 cpp
->fp
= fopen(cpp
->fn
, "r");
297 if (cpp
->fp
== NULL
) {
308 process_directive(gmx_cpp_t
*handlep
, const char *dname
, const char *dval
)
310 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
317 /* #ifdef or ifndef statement */
318 bIfdef
= (strcmp(dname
,"ifdef") == 0);
319 bIfndef
= (strcmp(dname
,"ifndef") == 0);
320 if (bIfdef
|| bIfndef
) {
321 if ((handle
->nifdef
> 0) && (handle
->ifdefs
[handle
->nifdef
-1] != eifTRUE
)) {
323 srenew(handle
->ifdefs
,handle
->nifdef
);
324 handle
->ifdefs
[handle
->nifdef
-1] = eifIGNORE
;
327 snew(name
,strlen(dval
)+1);
328 sscanf(dval
,"%s",name
);
329 for(i
=0; (i
<ndef
); i
++)
330 if (strcmp(defs
[i
].name
,name
) == 0)
333 srenew(handle
->ifdefs
,handle
->nifdef
);
334 if ((bIfdef
&& (i
< ndef
)) || (bIfndef
&& (i
== ndef
)))
335 handle
->ifdefs
[handle
->nifdef
-1] = eifTRUE
;
337 handle
->ifdefs
[handle
->nifdef
-1] = eifFALSE
;
343 /* #else statement */
344 if (strcmp(dname
,"else") == 0) {
345 if (handle
->nifdef
<= 0)
347 if (handle
->ifdefs
[handle
->nifdef
-1] == eifTRUE
)
348 handle
->ifdefs
[handle
->nifdef
-1] = eifFALSE
;
349 else if (handle
->ifdefs
[handle
->nifdef
-1] == eifFALSE
)
350 handle
->ifdefs
[handle
->nifdef
-1] = eifTRUE
;
354 /* #endif statement */
355 if (strcmp(dname
,"endif") == 0) {
356 if (handle
->nifdef
<= 0)
362 /* Check whether we're not ifdeffed out. The order of this statement
363 is important. It has to come after #ifdef, #else and #endif, but
364 anything else should be ignored. */
365 if (is_ifdeffed_out(handle
)) {
369 /* Check for include statements */
370 if (strcmp(dname
,"include") == 0) {
373 for(i1
=0; (i1
<strlen(dval
)); i1
++) {
374 if ((dval
[i1
] == '"') || (dval
[i1
] == '<') || (dval
[i1
] == '>')) {
389 strncpy(inc_fn
,dval
+i0
,len
);
393 fprintf(debug
,"Going to open include file '%s' i0 = %d, strlen = %d\n",
395 /* Open include file and store it as a child in the handle structure */
396 status
= cpp_open_file(inc_fn
,&(handle
->child
),NULL
);
398 if (status
!= eCPP_OK
) {
399 handle
->child
= NULL
;
402 /* Make a linked list of open files and move on to the include file */
403 handle
->child
->parent
= handle
;
404 *handlep
= handle
->child
;
409 /* #define statement */
410 if (strcmp(dname
,"define") == 0) {
411 /* Split it into name and value. */
413 while ((*ptr
!= '\0') && !isspace(*ptr
))
415 name
= gmx_strndup(dval
, ptr
- dval
);
417 while ((*ptr
!= '\0') && isspace(*ptr
))
420 add_define(name
, ptr
);
425 /* #undef statement */
426 if (strcmp(dname
,"undef") == 0) {
427 snew(name
,strlen(dval
)+1);
428 sscanf(dval
,"%s",name
);
429 for(i
=0; (i
<ndef
); i
++) {
430 if (strcmp(defs
[i
].name
,name
) == 0) {
437 for( ; (i
<ndef
-1); i
++) {
438 defs
[i
].name
= defs
[i
+1].name
;
439 defs
[i
].def
= defs
[i
+1].def
;
446 /* If we haven't matched anything, this is an unknown directive */
450 /* Return one whole line from the file into buf which holds at most n
451 characters, for subsequent processing. Returns integer status. This
452 routine also does all the "intelligent" work like processing cpp
453 directives and so on. Note that often the routine is called
454 recursively and no cpp directives are printed. */
455 int cpp_read_line(gmx_cpp_t
*handlep
,int n
,char buf
[])
457 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
459 const char *ptr
, *ptr2
;
465 return eCPP_INVALID_HANDLE
;
467 return eCPP_FILE_NOT_OPEN
;
469 bEOF
= feof(handle
->fp
);
471 /* Read the actual line now. */
472 if (fgets2(buf
,n
-1,handle
->fp
) == NULL
) {
473 /* Recheck EOF, since we could have been at the end before
474 * the fgets2 call, but we need to read past the end to know.
476 bEOF
= feof(handle
->fp
);
478 /* Something strange happened, fgets returned NULL,
479 * but we are not at EOF.
487 if (handle
->parent
== NULL
) {
490 cpp_close_file(handlep
);
491 *handlep
= handle
->parent
;
492 handle
->child
= NULL
;
493 return cpp_read_line(handlep
,n
,buf
);
496 if (n
> handle
->line_len
) {
497 handle
->line_len
= n
;
498 srenew(handle
->line
,n
);
500 strcpy(handle
->line
,buf
);
503 /* Now we've read a line! */
505 fprintf(debug
,"%s : %4d : %s\n",handle
->fn
,handle
->line_nr
,buf
);
507 /* Process directives if this line contains one */
508 if (find_directive(buf
, &dname
, &dval
))
510 status
= process_directive(handlep
, dname
, dval
);
511 if (status
!= eCPP_OK
)
513 /* Don't print lines with directives, go on to the next */
514 return cpp_read_line(handlep
,n
,buf
);
517 /* Check whether we're not ifdeffed out. The order of this statement
518 is important. It has to come after #ifdef, #else and #endif, but
519 anything else should be ignored. */
520 if (is_ifdeffed_out(handle
)) {
521 return cpp_read_line(handlep
,n
,buf
);
524 /* Check whether we have any defines that need to be replaced. Note
525 that we have to use a best fit algorithm, rather than first come
526 first go. We do this by sorting the defines on length first, and
527 then on alphabetical order. */
528 for(i
=0; (i
<ndef
); i
++) {
532 while ((ptr
= strstrw(ptr
,defs
[i
].name
)) != NULL
) {
534 ptr
+= strlen(defs
[i
].name
);
537 len
= strlen(buf
) + nn
*max(4,4+strlen(defs
[i
].def
)-strlen(defs
[i
].name
));
540 while ((ptr2
= strstrw(ptr
,defs
[i
].name
)) != NULL
) {
541 strncat(name
,ptr
,(int)(ptr2
-ptr
));
542 strcat(name
,defs
[i
].def
);
543 ptr
= ptr2
+ strlen(defs
[i
].name
);
555 char *cpp_cur_file(const gmx_cpp_t
*handlep
)
557 return (*handlep
)->fn
;
560 int cpp_cur_linenr(const gmx_cpp_t
*handlep
)
562 return (*handlep
)->line_nr
;
565 /* Close the file! Return integer status. */
566 int cpp_close_file(gmx_cpp_t
*handlep
)
569 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
572 return eCPP_INVALID_HANDLE
;
574 return eCPP_FILE_NOT_OPEN
;
576 fprintf(debug
,"Closing file %s\n",handle
->fn
);
578 if (NULL
!= handle
->cwd
) {
580 fprintf(debug
,"GMXCPP: chdir to %s\n",handle
->cwd
);
581 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
584 if (-1 == chdir(handle
->cwd
))
585 gmx_fatal(FARGS
,"Can not chdir to %s when processing topology: %s",
586 handle
->cwd
,strerror(errno
));
595 return eCPP_FILE_NOT_FOUND
;
597 return eCPP_FILE_NOT_OPEN
;
599 return eCPP_INTERRUPT
;
602 fprintf(debug
,"Strange stuff closing file, errno = %d",errno
);
607 if (NULL
!= handle
->fn
) {
611 if (NULL
!= handle
->line
) {
615 if (NULL
!= handle
->ifdefs
)
616 sfree(handle
->ifdefs
);
618 if (NULL
!= handle
->path
)
620 if (NULL
!= handle
->cwd
)
626 /* Return a string containing the error message coresponding to status
628 char *cpp_error(gmx_cpp_t
*handlep
,int status
)
631 const char *ecpp
[] = {
632 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
633 "Invalid file handle",
634 "File not open", "Unknown error", "Error status out of range"
636 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
639 return (char *)ecpp
[eCPP_INVALID_HANDLE
];
641 if ((status
< 0) || (status
>= eCPP_NR
))
644 sprintf(buf
,"%s - File %s, line %d\nLast line read:\n'%s'",
646 (handle
&& handle
->fn
) ? handle
->fn
: "unknown",
647 (handle
) ? handle
->line_nr
: -1,
648 handle
->line
? handle
->line
: "");