fixed segv in grompp due to gmxcpp not checking for #include statements without delim...
[gromacs.git] / src / gmxlib / gmxcpp.c
blob10be597e686601489dc38eb852948ffddf426083
1 /*
2 *
3 * This source code is part of
4 *
5 * G R O M A C S
6 *
7 * GROningen MAchine for Chemical Simulations
8 *
9 * VERSION 3.2.0
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
32 * And Hey:
33 * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 #include <sys/types.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <math.h>
43 #include <string.h>
44 #include <errno.h>
45 #include <limits.h>
46 #include <ctype.h>
48 /* Necessary for getcwd */
49 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
50 #include <direct.h>
51 #include <io.h>
52 #endif
54 #include "string2.h"
55 #include "smalloc.h"
56 #include "futil.h"
57 #include "macros.h"
58 #include "gmx_fatal.h"
59 #include "gmxcpp.h"
61 typedef struct {
62 char *name;
63 char *def;
64 } t_define;
66 static int ndef = 0;
67 static t_define *defs = NULL;
68 static int nincl = 0;
69 static char **incl = 0;
71 /* enum used for handling ifdefs */
72 enum { eifTRUE, eifFALSE, eifIGNORE, eifNR };
74 typedef struct gmx_cpp {
75 FILE *fp;
76 char *path,*cwd;
77 char *fn;
78 int line_len;
79 char *line;
80 int line_nr;
81 int nifdef;
82 int *ifdefs;
83 struct gmx_cpp *child,*parent;
84 } gmx_cpp;
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)
93 const char *ptr;
95 while ((ptr = strstr(buf,word)) != NULL) {
96 /* Check if we did not find part of a longer word */
97 if (ptr &&
98 is_word_end(ptr[strlen(word)]) &&
99 (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
100 return ptr;
102 buf = ptr + strlen(word);
104 return NULL;
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 */
112 if (*buf != '#')
113 return FALSE;
114 /* Skip the hash and any space after it */
115 ++buf;
116 while (isspace(*buf)) ++buf;
117 /* Set the name pointer and find the next space */
118 *name = buf;
119 while (*buf != 0 && !isspace(*buf)) ++buf;
120 /* Set the end of the name here, and skip any space */
121 if (*buf != 0)
123 *buf = 0;
124 ++buf;
125 while (isspace(*buf)) ++buf;
127 /* Check if anything is remaining */
128 *val = (*buf != 0) ? buf : NULL;
129 return TRUE;
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)
139 int i;
141 if (include == NULL)
142 return;
144 for(i=0; (i<nincl); i++)
145 if (strcmp(incl[i],include) == 0)
146 break;
147 if (i == nincl) {
148 nincl++;
149 srenew(incl,nincl);
150 incl[nincl-1] = strdup(include);
154 static void add_define(const char *name, const char *value)
156 int i;
158 for(i=0; (i<ndef); i++) {
159 if (strcmp(defs[i].name,name) == 0) {
160 break;
163 if (i == ndef) {
164 ndef++;
165 srenew(defs,ndef);
166 i = ndef - 1;
167 defs[i].name = strdup(name);
169 else if (defs[i].def) {
170 if (debug)
171 fprintf(debug,"Overriding define %s\n",name);
172 sfree(defs[i].def);
174 if (value && strlen(value) > 0)
175 defs[i].def = strdup(value);
176 else
177 defs[i].def = NULL;
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)
184 gmx_cpp_t cpp;
185 char *buf,*pdum;
186 char *ptr, *ptr2;
187 int i;
188 unsigned int i1;
190 /* First process options, they might be necessary for opening files
191 (especially include statements). */
192 i = 0;
193 if (cppopts) {
194 while(cppopts[i]) {
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], '=');
201 if (ptr)
203 buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
204 add_define(buf, ptr + 1);
205 sfree(buf);
207 else
209 add_define(cppopts[i] + 2, NULL);
212 i++;
215 if (debug)
216 fprintf(debug,"Added %d command line arguments",i);
218 snew(cpp,1);
219 *handle = cpp;
220 cpp->fn = NULL;
221 /* Find the file. First check whether it is in the current directory. */
222 if (gmx_fexist(filenm))
224 cpp->fn = strdup(filenm);
226 else
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);
233 if (gmx_fexist(buf))
235 cpp->fn = buf;
236 break;
238 sfree(buf);
240 /* If still not found, check the Gromacs library search path. */
241 if (!cpp->fn)
243 cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
246 if (!cpp->fn)
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))
259 ptr = ptr2;
261 if(ptr==NULL)
263 cpp->path = NULL;
264 cpp->cwd = NULL;
266 else
268 cpp->path = cpp->fn;
269 *ptr = '\0';
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);
275 _chdir(cpp->path);
276 #else
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));
282 #endif
284 if (NULL != debug)
285 fprintf(debug,"GMXCPP: chdir to %s\n",cpp->path);
287 cpp->line_len= 0;
288 cpp->line = NULL;
289 cpp->line_nr = 0;
290 cpp->nifdef = 0;
291 cpp->ifdefs = NULL;
292 cpp->child = NULL;
293 cpp->parent = NULL;
294 if (cpp->fp == NULL) {
295 cpp->fp = fopen(cpp->fn, "r");
297 if (cpp->fp == NULL) {
298 switch(errno) {
299 case EINVAL:
300 default:
301 return eCPP_UNKNOWN;
304 return eCPP_OK;
307 static int
308 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
310 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
311 int i,i0,len,status;
312 unsigned int i1;
313 char *inc_fn,*name;
314 const char *ptr;
315 int bIfdef,bIfndef;
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)) {
322 handle->nifdef++;
323 srenew(handle->ifdefs,handle->nifdef);
324 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
326 else {
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)
331 break;
332 handle->nifdef++;
333 srenew(handle->ifdefs,handle->nifdef);
334 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
335 handle->ifdefs[handle->nifdef-1] = eifTRUE;
336 else
337 handle->ifdefs[handle->nifdef-1] = eifFALSE;
338 sfree(name);
340 return eCPP_OK;
343 /* #else statement */
344 if (strcmp(dname,"else") == 0) {
345 if (handle->nifdef <= 0)
346 return eCPP_SYNTAX;
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;
351 return eCPP_OK;
354 /* #endif statement */
355 if (strcmp(dname,"endif") == 0) {
356 if (handle->nifdef <= 0)
357 return eCPP_SYNTAX;
358 handle->nifdef--;
359 return eCPP_OK;
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)) {
366 return eCPP_OK;
369 /* Check for include statements */
370 if (strcmp(dname,"include") == 0) {
371 len = -1;
372 i0 = 0;
373 for(i1=0; (i1<strlen(dval)); i1++) {
374 if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>')) {
375 if (len == -1) {
376 i0 = i1+1;
377 len = 0;
379 else
380 break;
382 else if (len >= 0)
383 len++;
385 if (len == -1) {
386 return eCPP_SYNTAX;
388 snew(inc_fn,len+1);
389 strncpy(inc_fn,dval+i0,len);
390 inc_fn[len] = '\0';
392 if (debug)
393 fprintf(debug,"Going to open include file '%s' i0 = %d, strlen = %d\n",
394 inc_fn,i0,len);
395 /* Open include file and store it as a child in the handle structure */
396 status = cpp_open_file(inc_fn,&(handle->child),NULL);
397 sfree(inc_fn);
398 if (status != eCPP_OK) {
399 handle->child = NULL;
400 return status;
402 /* Make a linked list of open files and move on to the include file */
403 handle->child->parent = handle;
404 *handlep = handle->child;
405 handle = *handlep;
406 return eCPP_OK;
409 /* #define statement */
410 if (strcmp(dname,"define") == 0) {
411 /* Split it into name and value. */
412 ptr = dval;
413 while ((*ptr != '\0') && !isspace(*ptr))
414 ptr++;
415 name = gmx_strndup(dval, ptr - dval);
417 while ((*ptr != '\0') && isspace(*ptr))
418 ptr++;
420 add_define(name, ptr);
421 sfree(name);
422 return eCPP_OK;
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) {
431 sfree(defs[i].name);
432 sfree(defs[i].def);
433 break;
436 sfree(name);
437 for( ; (i<ndef-1); i++) {
438 defs[i].name = defs[i+1].name;
439 defs[i].def = defs[i+1].def;
441 ndef--;
443 return eCPP_OK;
446 /* If we haven't matched anything, this is an unknown directive */
447 return eCPP_SYNTAX;
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;
458 int i,nn,len,status;
459 const char *ptr, *ptr2;
460 char *name;
461 char *dname, *dval;
462 gmx_bool bEOF;
464 if (!handle)
465 return eCPP_INVALID_HANDLE;
466 if (!handle->fp)
467 return eCPP_FILE_NOT_OPEN;
469 bEOF = feof(handle->fp);
470 if (!bEOF) {
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);
477 if (!bEOF) {
478 /* Something strange happened, fgets returned NULL,
479 * but we are not at EOF.
481 return eCPP_UNKNOWN;
486 if (bEOF) {
487 if (handle->parent == NULL) {
488 return eCPP_EOF;
490 cpp_close_file(handlep);
491 *handlep = handle->parent;
492 handle->child = NULL;
493 return cpp_read_line(handlep,n,buf);
495 else {
496 if (n > handle->line_len) {
497 handle->line_len = n;
498 srenew(handle->line,n);
500 strcpy(handle->line,buf);
501 handle->line_nr++;
503 /* Now we've read a line! */
504 if (debug)
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)
512 return status;
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++) {
529 if (defs[i].def) {
530 nn = 0;
531 ptr = buf;
532 while ((ptr = strstrw(ptr,defs[i].name)) != NULL) {
533 nn++;
534 ptr += strlen(defs[i].name);
536 if (nn > 0) {
537 len = strlen(buf) + nn*max(4,4+strlen(defs[i].def)-strlen(defs[i].name));
538 snew(name,len);
539 ptr = buf;
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);
545 strcat(name,ptr);
546 strcpy(buf,name);
547 sfree(name);
552 return eCPP_OK;
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)
568 int i;
569 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
571 if (!handle)
572 return eCPP_INVALID_HANDLE;
573 if (!handle->fp)
574 return eCPP_FILE_NOT_OPEN;
575 if (debug)
576 fprintf(debug,"Closing file %s\n",handle->fn);
577 fclose(handle->fp);
578 if (NULL != handle->cwd) {
579 if (NULL != debug)
580 fprintf(debug,"GMXCPP: chdir to %s\n",handle->cwd);
581 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
582 _chdir(handle->cwd);
583 #else
584 if (-1 == chdir(handle->cwd))
585 gmx_fatal(FARGS,"Can not chdir to %s when processing topology: %s",
586 handle->cwd,strerror(errno));
587 #endif
590 if (0)
591 switch(errno) {
592 case 0:
593 break;
594 case ENOENT:
595 return eCPP_FILE_NOT_FOUND;
596 case EBADF:
597 return eCPP_FILE_NOT_OPEN;
598 case EINTR:
599 return eCPP_INTERRUPT;
600 default:
601 if (debug)
602 fprintf(debug,"Strange stuff closing file, errno = %d",errno);
603 return eCPP_UNKNOWN;
605 handle->fp = NULL;
606 handle->line_nr = 0;
607 if (NULL != handle->fn) {
608 sfree(handle->fn);
609 handle->fn = NULL;
611 if (NULL != handle->line) {
612 sfree(handle->line);
613 handle->line = NULL;
615 if (NULL != handle->ifdefs)
616 sfree(handle->ifdefs);
617 handle->nifdef = 0;
618 if (NULL != handle->path)
619 sfree(handle->path);
620 if (NULL != handle->cwd)
621 sfree(handle->cwd);
623 return eCPP_OK;
626 /* Return a string containing the error message coresponding to status
627 variable */
628 char *cpp_error(gmx_cpp_t *handlep,int status)
630 char buf[256];
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;
638 if (!handle)
639 return (char *)ecpp[eCPP_INVALID_HANDLE];
641 if ((status < 0) || (status >= eCPP_NR))
642 status = eCPP_NR;
644 sprintf(buf,"%s - File %s, line %d\nLast line read:\n'%s'",
645 ecpp[status],
646 (handle && handle->fn) ? handle->fn : "unknown",
647 (handle) ? handle->line_nr : -1,
648 handle->line ? handle->line : "");
650 return strdup(buf);