Don't use POSIX fnmatch() for pattern matching.
[gromacs/qmmm-gamess-us.git] / src / gmxlib / gmxcpp.c
blobd8f0d13ccd1b31ee51524902dec12da86c4f324a
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 "gmxcpp.h"
60 typedef struct {
61 char *name;
62 char *def;
63 } t_define;
65 static int ndef = 0;
66 static t_define *defs = NULL;
67 static int nincl = 0;
68 static char **incl = 0;
70 /* enum used for handling ifdefs */
71 enum { eifTRUE, eifFALSE, eifIGNORE, eifNR };
73 typedef struct gmx_cpp {
74 FILE *fp;
75 char *path,*cwd;
76 char *fn;
77 int line_len;
78 char *line;
79 int line_nr;
80 int nifdef;
81 int *ifdefs;
82 struct gmx_cpp *child,*parent;
83 } gmx_cpp;
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)
92 char *ptr;
94 while ((ptr = strstr(buf,word)) != NULL) {
95 /* Check if we did not find part of a longer word */
96 if (ptr &&
97 is_blank_end(ptr[strlen(word)]) &&
98 (((ptr > buf) && is_blank_end(ptr[-1])) || (ptr == buf)))
99 return ptr;
101 buf = ptr + strlen(word);
103 return NULL;
106 static void add_include(const char *include)
108 int i;
110 if (include == NULL)
111 return;
113 for(i=0; (i<nincl); i++)
114 if (strcmp(incl[i],include) == 0)
115 break;
116 if (i == nincl) {
117 nincl++;
118 srenew(incl,nincl);
119 incl[nincl-1] = strdup(include);
123 static void add_define(const char *define)
125 int i;
126 const char *ptr;
127 char name[256];
129 sscanf(define,"%s%n",name,&i);
130 ptr = define + i;
132 while ((*ptr != '\0') && isspace(*ptr))
133 ptr++;
135 for(i=0; (i<ndef); i++) {
136 if (strcmp(defs[i].name,name) == 0) {
137 break;
140 if (i == ndef) {
141 ndef++;
142 srenew(defs,ndef);
143 i = ndef - 1;
144 defs[i].name = strdup(name);
146 else if (defs[i].def) {
147 if (debug)
148 fprintf(debug,"Overriding define %s\n",name);
149 sfree(defs[i].def);
151 if (strlen(ptr) > 0)
152 defs[i].def = strdup(ptr);
153 else
154 defs[i].def = NULL;
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)
161 gmx_cpp_t cpp;
162 char *buf,*ptr,*pdum;
163 int i;
164 unsigned int i1;
166 /* First process options, they might be necessary for opening files
167 (especially include statements). */
168 i = 0;
169 if (cppopts) {
170 while(cppopts[i]) {
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);
175 i++;
178 if (debug)
179 fprintf(debug,"Added %d command line arguments",i);
181 snew(cpp,1);
182 *handle = cpp;
183 ptr = strrchr(filenm,'/');
184 if (NULL == ptr) {
185 cpp->path = NULL;
186 cpp->cwd = NULL;
187 cpp->fn = strdup(filenm);
189 else {
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);
197 _chdir(cpp->path);
198 #else
199 pdum=getcwd(cpp->cwd,STRLEN);
200 chdir(cpp->path);
201 #endif
203 if (NULL != debug)
204 fprintf(debug,"GMXCPP: chdir to %s\n",cpp->path);
206 cpp->line_len= 0;
207 cpp->line = NULL;
208 cpp->line_nr = 0;
209 cpp->nifdef = 0;
210 cpp->ifdefs = NULL;
211 cpp->child = NULL;
212 cpp->parent = NULL;
213 i = 0;
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);
217 sfree(cpp->fn);
218 cpp->fn = strdup(buf);
219 sfree(buf);
220 i++;
222 if (cpp->fp == NULL) {
223 sfree(cpp->fn);
224 cpp->fn = strdup(filenm);
225 cpp->fp = libopen(filenm);
227 if (cpp->fp == NULL) {
228 switch(errno) {
229 case EINVAL:
230 default:
231 return eCPP_UNKNOWN;
234 return eCPP_OK;
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;
246 unsigned int i1;
247 char *inc_fn,*ptr,*ptr2,*name;
248 int bIfdef,bIfndef;
250 if (!handle)
251 return eCPP_INVALID_HANDLE;
252 if (!handle->fp)
253 return eCPP_FILE_NOT_OPEN;
255 if (feof(handle->fp) || (fgets2(buf,n-1,handle->fp) == NULL)) {
256 if (handle->parent == NULL)
257 return eCPP_EOF;
258 cpp_close_file(handlep);
259 *handlep = handle->parent;
260 handle->child = NULL;
261 return cpp_read_line(handlep,n,buf);
263 else {
264 if (n > handle->line_len) {
265 handle->line_len = n;
266 srenew(handle->line,n);
268 strcpy(handle->line,buf);
269 handle->line_nr++;
271 /* Now we've read a line! */
272 if (debug)
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)) {
281 handle->nifdef++;
282 srenew(handle->ifdefs,handle->nifdef);
283 handle->ifdefs[handle->nifdef-1] = eifIGNORE;
285 else {
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)
290 break;
291 handle->nifdef++;
292 srenew(handle->ifdefs,handle->nifdef);
293 if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
294 handle->ifdefs[handle->nifdef-1] = eifTRUE;
295 else
296 handle->ifdefs[handle->nifdef-1] = eifFALSE;
297 sfree(name);
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)
306 return eCPP_SYNTAX;
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)
319 return eCPP_SYNTAX;
320 handle->nifdef--;
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) {
335 len = -1;
336 i0 = 0;
337 for(i1=0; (i1<strlen(buf)); i1++) {
338 if ((buf[i1] == '"') || (buf[i1] == '<') || (buf[i1] == '>')) {
339 if (len == -1) {
340 i0 = i1+1;
341 len = 0;
343 else
344 break;
346 else if (len >= 0)
347 len++;
349 snew(inc_fn,len+1);
350 strncpy(inc_fn,buf+i0,len);
351 inc_fn[len] = '\0';
353 if (debug)
354 fprintf(debug,"Going to open include file '%s' i0 = %d, strlen = %d\n",
355 inc_fn,i0,len);
356 /* Open include file and store it as a child in the handle structure */
357 status = cpp_open_file(inc_fn,&(handle->child),NULL);
358 sfree(inc_fn);
359 if (status != eCPP_OK) {
360 handle->child = NULL;
361 return status;
363 /* Make a linked list of open files and move on to the include file */
364 handle->child->parent = handle;
365 *handlep = handle->child;
366 handle = *handlep;
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) {
373 add_define(buf+8);
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) {
384 sfree(defs[i].name);
385 sfree(defs[i].def);
386 break;
389 sfree(name);
390 for( ; (i<ndef-1); i++) {
391 defs[i].name = defs[i+1].name;
392 defs[i].def = defs[i+1].def;
394 ndef--;
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++) {
405 if (defs[i].def) {
406 nn = 0;
407 ptr = buf;
408 while ((ptr = strstrw(ptr,defs[i].name)) != NULL) {
409 nn++;
410 ptr += strlen(defs[i].name);
412 if (nn > 0) {
413 len = strlen(buf) + nn*max(4,4+strlen(defs[i].def)-strlen(defs[i].name));
414 snew(name,len);
415 ptr = buf;
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);
421 strcat(name,ptr);
422 strcpy(buf,name);
423 sfree(name);
428 return eCPP_OK;
431 /* Close the file! Return integer status. */
432 int cpp_close_file(gmx_cpp_t *handlep)
434 int i;
435 gmx_cpp_t handle = (gmx_cpp_t)*handlep;
437 if (!handle)
438 return eCPP_INVALID_HANDLE;
439 if (!handle->fp)
440 return eCPP_FILE_NOT_OPEN;
441 if (debug)
442 fprintf(debug,"Closing file %s\n",handle->fn);
443 fclose(handle->fp);
444 if (NULL != handle->cwd) {
445 if (NULL != debug)
446 fprintf(debug,"GMXCPP: chdir to %s\n",handle->cwd);
447 #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
448 _chdir(handle->cwd);
449 #else
450 chdir(handle->cwd);
451 #endif
454 if (0)
455 switch(errno) {
456 case 0:
457 break;
458 case ENOENT:
459 return eCPP_FILE_NOT_FOUND;
460 case EBADF:
461 return eCPP_FILE_NOT_OPEN;
462 case EINTR:
463 return eCPP_INTERRUPT;
464 default:
465 if (debug)
466 fprintf(debug,"Strange stuff closing file, errno = %d",errno);
467 return eCPP_UNKNOWN;
469 handle->fp = NULL;
470 handle->line_nr = 0;
471 if (NULL != handle->fn) {
472 sfree(handle->fn);
473 handle->fn = NULL;
475 if (NULL != handle->line) {
476 sfree(handle->line);
477 handle->line = NULL;
479 if (NULL != handle->ifdefs)
480 sfree(handle->ifdefs);
481 handle->nifdef = 0;
482 if (NULL != handle->path)
483 sfree(handle->path);
484 if (NULL != handle->cwd)
485 sfree(handle->cwd);
487 return eCPP_OK;
490 /* Return a string containing the error message coresponding to status
491 variable */
492 char *cpp_error(gmx_cpp_t *handlep,int status)
494 char buf[256];
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;
502 if (!handle)
503 return (char *)ecpp[eCPP_INVALID_HANDLE];
505 if ((status < 0) || (status >= eCPP_NR))
506 status = eCPP_NR;
508 sprintf(buf,"%s - File %s, line %d\nLast line read:\n'%s'",
509 ecpp[status],
510 (handle && handle->fn) ? handle->fn : "unknown",
511 (handle) ? handle->line_nr : -1,
512 handle->line ? handle->line : "");
514 return strdup(buf);