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__)
66 static t_define
*defs
= NULL
;
68 static char **incl
= 0;
70 /* enum used for handling ifdefs */
71 enum { eifTRUE
, eifFALSE
, eifIGNORE
, eifNR
};
73 typedef struct gmx_cpp
{
82 struct gmx_cpp
*child
,*parent
;
85 static bool is_blank_end(char c
)
87 return ((c
== ' ') || (c
== '\t') || (c
== '\0') || (c
== '\n'));
90 static char *strstrw(const char *buf
,const char *word
)
94 while ((ptr
= strstr(buf
,word
)) != NULL
) {
95 /* Check if we did not find part of a longer word */
97 is_blank_end(ptr
[strlen(word
)]) &&
98 (((ptr
> buf
) && is_blank_end(ptr
[-1])) || (ptr
== buf
)))
101 buf
= ptr
+ strlen(word
);
106 static void add_include(const char *include
)
113 for(i
=0; (i
<nincl
); i
++)
114 if (strcmp(incl
[i
],include
) == 0)
119 incl
[nincl
-1] = strdup(include
);
123 static void add_define(const char *define
)
129 sscanf(define
,"%s%n",name
,&i
);
132 while ((*ptr
!= '\0') && isspace(*ptr
))
135 for(i
=0; (i
<ndef
); i
++) {
136 if (strcmp(defs
[i
].name
,name
) == 0) {
144 defs
[i
].name
= strdup(name
);
146 else if (defs
[i
].def
) {
148 fprintf(debug
,"Overriding define %s\n",name
);
152 defs
[i
].def
= strdup(ptr
);
157 /* Open the file to be processed. The handle variable holds internal
158 info for the cpp emulator. Return integer status */
159 int cpp_open_file(const char *filenm
,gmx_cpp_t
*handle
, char **cppopts
)
162 char *buf
,*ptr
,*pdum
;
166 /* First process options, they might be necessary for opening files
167 (especially include statements). */
171 if (strstr(cppopts
[i
],"-I") == cppopts
[i
])
172 add_include(cppopts
[i
]+2);
173 if (strstr(cppopts
[i
],"-D") == cppopts
[i
])
174 add_define(cppopts
[i
]+2);
179 fprintf(debug
,"Added %d command line arguments",i
);
183 ptr
= strrchr(filenm
,'/');
187 cpp
->fn
= strdup(filenm
);
190 cpp
->path
= strdup(filenm
);
191 cpp
->path
[ptr
-filenm
] = '\0';
192 cpp
->fn
= strdup(ptr
+1);
193 snew(cpp
->cwd
,STRLEN
);
195 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
196 pdum
=_getcwd(cpp
->cwd
,STRLEN
);
199 pdum
=getcwd(cpp
->cwd
,STRLEN
);
204 fprintf(debug
,"GMXCPP: chdir to %s\n",cpp
->path
);
214 while (((cpp
->fp
= fopen(cpp
->fn
,"r")) == NULL
) && (i
<nincl
)) {
215 snew(buf
,strlen(incl
[i
])+strlen(filenm
)+2);
216 sprintf(buf
,"%s/%s",incl
[i
],filenm
);
218 cpp
->fn
= strdup(buf
);
222 if (cpp
->fp
== NULL
) {
224 cpp
->fn
= strdup(filenm
);
225 cpp
->fp
= libopen(filenm
);
227 if (cpp
->fp
== NULL
) {
237 /* Return one whole line from the file into buf which holds at most n
238 characters, for subsequent processing. Returns integer status. This
239 routine also does all the "intelligent" work like processing cpp
240 directives and so on. Note that often the routine is called
241 recursively and no cpp directives are printed. */
242 int cpp_read_line(gmx_cpp_t
*handlep
,int n
,char buf
[])
244 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
245 int i
,i0
,nn
,len
,status
;
247 char *inc_fn
,*ptr
,*ptr2
,*name
;
251 return eCPP_INVALID_HANDLE
;
253 return eCPP_FILE_NOT_OPEN
;
255 if (feof(handle
->fp
) || (fgets2(buf
,n
-1,handle
->fp
) == NULL
)) {
256 if (handle
->parent
== NULL
)
258 cpp_close_file(handlep
);
259 *handlep
= handle
->parent
;
260 handle
->child
= NULL
;
261 return cpp_read_line(handlep
,n
,buf
);
264 if (n
> handle
->line_len
) {
265 handle
->line_len
= n
;
266 srenew(handle
->line
,n
);
268 strcpy(handle
->line
,buf
);
271 /* Now we've read a line! */
273 fprintf(debug
,"%s : %4d : %s\n",handle
->fn
,handle
->line_nr
,buf
);
274 set_warning_line(handle
->fn
,handle
->line_nr
);
276 /* #ifdef or ifndef statement */
277 bIfdef
= (strstrw(buf
,"#ifdef") != NULL
);
278 bIfndef
= (strstrw(buf
,"#ifndef") != NULL
);
279 if (bIfdef
|| bIfndef
) {
280 if ((handle
->nifdef
> 0) && (handle
->ifdefs
[handle
->nifdef
-1] != eifTRUE
)) {
282 srenew(handle
->ifdefs
,handle
->nifdef
);
283 handle
->ifdefs
[handle
->nifdef
-1] = eifIGNORE
;
286 snew(name
,strlen(buf
));
287 status
= sscanf(buf
,"%*s %s",name
);
288 for(i
=0; (i
<ndef
); i
++)
289 if (strcmp(defs
[i
].name
,name
) == 0)
292 srenew(handle
->ifdefs
,handle
->nifdef
);
293 if ((bIfdef
&& (i
< ndef
)) || (bIfndef
&& (i
== ndef
)))
294 handle
->ifdefs
[handle
->nifdef
-1] = eifTRUE
;
296 handle
->ifdefs
[handle
->nifdef
-1] = eifFALSE
;
299 /* Don't print lines with ifdef or ifndef, go on to the next */
300 return cpp_read_line(handlep
,n
,buf
);
303 /* #else statement */
304 if (strstrw(buf
,"#else") != NULL
) {
305 if (handle
->nifdef
<= 0)
307 if (handle
->ifdefs
[handle
->nifdef
-1] == eifTRUE
)
308 handle
->ifdefs
[handle
->nifdef
-1] = eifFALSE
;
309 else if (handle
->ifdefs
[handle
->nifdef
-1] == eifFALSE
)
310 handle
->ifdefs
[handle
->nifdef
-1] = eifTRUE
;
312 /* Don't print lines with else, go on to the next */
313 return cpp_read_line(handlep
,n
,buf
);
316 /* #endif statement */
317 if (strstrw(buf
,"#endif") != NULL
) {
318 if (handle
->nifdef
<= 0)
322 /* Don't print lines with endif, go on to the next */
323 return cpp_read_line(handlep
,n
,buf
);
326 /* Check whether we're not ifdeffed out. The order of this statement
327 is important. It has to come after #ifdef, #else and #endif, but
328 anything else should be ignored. */
329 if ((handle
->nifdef
> 0) && (handle
->ifdefs
[handle
->nifdef
-1] != eifTRUE
)) {
330 return cpp_read_line(handlep
,n
,buf
);
333 /* Check for include statements */
334 if (strstrw(buf
,"#include") != NULL
) {
337 for(i1
=0; (i1
<strlen(buf
)); i1
++) {
338 if ((buf
[i1
] == '"') || (buf
[i1
] == '<') || (buf
[i1
] == '>')) {
350 strncpy(inc_fn
,buf
+i0
,len
);
354 fprintf(debug
,"Going to open include file '%s' i0 = %d, strlen = %d\n",
356 /* Open include file and store it as a child in the handle structure */
357 status
= cpp_open_file(inc_fn
,&(handle
->child
),NULL
);
359 if (status
!= eCPP_OK
) {
360 handle
->child
= NULL
;
363 /* Make a linked list of open files and move on to the include file */
364 handle
->child
->parent
= handle
;
365 *handlep
= handle
->child
;
367 /* Don't print lines with include, go on to the next */
368 return cpp_read_line(handlep
,n
,buf
);
371 /* #define statement */
372 if (strstrw(buf
,"#define") != NULL
) {
375 return cpp_read_line(handlep
,n
,buf
);
378 /* #undef statement */
379 if (strstrw(buf
,"#undef") != NULL
) {
380 snew(name
,strlen(buf
));
381 status
= sscanf(buf
,"%*s %s",name
);
382 for(i
=0; (i
<ndef
); i
++) {
383 if (strcmp(defs
[i
].name
,name
) == 0) {
390 for( ; (i
<ndef
-1); i
++) {
391 defs
[i
].name
= defs
[i
+1].name
;
392 defs
[i
].def
= defs
[i
+1].def
;
396 /* Don't print lines with undef, go on to the next */
397 return cpp_read_line(handlep
,n
,buf
);
400 /* Check whether we have any defines that need to be replaced. Note
401 that we have to use a best fit algorithm, rather than first come
402 first go. We do this by sorting the defines on length first, and
403 then on alphabetical order. */
404 for(i
=0; (i
<ndef
); i
++) {
408 while ((ptr
= strstrw(ptr
,defs
[i
].name
)) != NULL
) {
410 ptr
+= strlen(defs
[i
].name
);
413 len
= strlen(buf
) + nn
*max(4,4+strlen(defs
[i
].def
)-strlen(defs
[i
].name
));
416 while ((ptr2
= strstrw(ptr
,defs
[i
].name
)) != NULL
) {
417 strncat(name
,ptr
,(int)(ptr2
-ptr
));
418 strcat(name
,defs
[i
].def
);
419 ptr
= ptr2
+ strlen(defs
[i
].name
);
431 /* Close the file! Return integer status. */
432 int cpp_close_file(gmx_cpp_t
*handlep
)
435 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
438 return eCPP_INVALID_HANDLE
;
440 return eCPP_FILE_NOT_OPEN
;
442 fprintf(debug
,"Closing file %s\n",handle
->fn
);
444 if (NULL
!= handle
->cwd
) {
446 fprintf(debug
,"GMXCPP: chdir to %s\n",handle
->cwd
);
447 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
459 return eCPP_FILE_NOT_FOUND
;
461 return eCPP_FILE_NOT_OPEN
;
463 return eCPP_INTERRUPT
;
466 fprintf(debug
,"Strange stuff closing file, errno = %d",errno
);
471 if (NULL
!= handle
->fn
) {
475 if (NULL
!= handle
->line
) {
479 if (NULL
!= handle
->ifdefs
)
480 sfree(handle
->ifdefs
);
482 if (NULL
!= handle
->path
)
484 if (NULL
!= handle
->cwd
)
490 /* Return a string containing the error message coresponding to status
492 char *cpp_error(gmx_cpp_t
*handlep
,int status
)
495 const char *ecpp
[] = {
496 "OK", "File not found", "End of file", "Syntax error", "Interrupted",
497 "Invalid file handle",
498 "File not open", "Unknown error", "Error status out of range"
500 gmx_cpp_t handle
= (gmx_cpp_t
)*handlep
;
503 return (char *)ecpp
[eCPP_INVALID_HANDLE
];
505 if ((status
< 0) || (status
>= eCPP_NR
))
508 sprintf(buf
,"%s - File %s, line %d\nLast line read:\n'%s'",
510 (handle
&& handle
->fn
) ? handle
->fn
: "unknown",
511 (handle
) ? handle
->line_nr
: -1,
512 handle
->line
? handle
->line
: "");