Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / gmxlib / gmxcpp.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team,
6  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41 #include "gmx_header_config.h"
42
43 #include <sys/types.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <math.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <limits.h>
50 #include <ctype.h>
51
52 /* Necessary for getcwd */
53 #ifdef GMX_NATIVE_WINDOWS
54 #include <direct.h>
55 #include <io.h>
56 #endif
57
58 #include "string2.h"
59 #include "smalloc.h"
60 #include "futil.h"
61 #include "macros.h"
62 #include "gmx_fatal.h"
63 #include "gmxcpp.h"
64
65 typedef struct {
66   char *name;
67   char *def;
68 } t_define;
69
70 static int      ndef   = 0;
71 static t_define *defs  = NULL;
72 static int      nincl  = 0;
73 static char     **incl = 0;
74
75 /* enum used for handling ifdefs */
76 enum { eifTRUE, eifFALSE, eifIGNORE, eifNR };
77
78 typedef struct gmx_cpp {
79   FILE     *fp;
80   char     *path,*cwd;
81   char     *fn;
82   int      line_len;
83   char     *line;
84   int      line_nr;
85   int      nifdef;
86   int      *ifdefs;
87   struct   gmx_cpp *child,*parent;
88 } gmx_cpp;
89
90 static gmx_bool is_word_end(char c)
91 {
92   return !(isalnum(c) || c == '_');
93 }
94
95 static const char *strstrw(const char *buf,const char *word)
96 {
97   const char *ptr;
98
99   while ((ptr = strstr(buf,word)) != NULL) {
100     /* Check if we did not find part of a longer word */
101     if (ptr && 
102         is_word_end(ptr[strlen(word)]) &&
103         (((ptr > buf) && is_word_end(ptr[-1])) || (ptr == buf)))
104       return ptr;
105       
106     buf = ptr + strlen(word);
107   }
108   return NULL;
109 }
110
111 static gmx_bool find_directive(char *buf, char **name, char **val)
112 {
113   /* Skip initial whitespace */
114   while (isspace(*buf)) ++buf;
115   /* Check if this is a directive */
116   if (*buf != '#')
117     return FALSE;
118   /* Skip the hash and any space after it */
119   ++buf;
120   while (isspace(*buf)) ++buf;
121   /* Set the name pointer and find the next space */
122   *name = buf;
123   while (*buf != 0 && !isspace(*buf)) ++buf;
124   /* Set the end of the name here, and skip any space */
125   if (*buf != 0)
126   {
127     *buf = 0;
128     ++buf;
129     while (isspace(*buf)) ++buf;
130   }
131   /* Check if anything is remaining */
132   *val = (*buf != 0) ? buf : NULL;
133   return TRUE;
134 }
135
136 static gmx_bool is_ifdeffed_out(gmx_cpp_t handle)
137 {
138   return ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE));
139 }
140
141 static void add_include(const char *include)
142 {
143   int i;
144   
145   if (include == NULL)
146     return;
147     
148   for(i=0; (i<nincl); i++)
149     if (strcmp(incl[i],include) == 0)
150       break;
151   if (i == nincl) {
152     nincl++;
153     srenew(incl,nincl);
154     incl[nincl-1] = strdup(include);
155   }
156 }
157
158 static void add_define(const char *name, const char *value)
159 {
160   int  i;
161
162   for(i=0; (i<ndef); i++) {
163     if (strcmp(defs[i].name,name) == 0) {
164       break;
165     }
166   }
167   if (i == ndef) {
168     ndef++;
169     srenew(defs,ndef);
170     i = ndef - 1;
171     defs[i].name = strdup(name);
172   }
173   else if (defs[i].def) {
174     if (debug)
175       fprintf(debug,"Overriding define %s\n",name);
176     sfree(defs[i].def);
177   }
178   if (value && strlen(value) > 0)
179     defs[i].def  = strdup(value);
180   else
181     defs[i].def  = NULL;
182 }
183
184 /* Open the file to be processed. The handle variable holds internal
185    info for the cpp emulator. Return integer status */
186 int cpp_open_file(const char *filenm,gmx_cpp_t *handle, char **cppopts)
187 {
188   gmx_cpp_t cpp;
189   char *buf,*pdum;
190   char *ptr, *ptr2;
191   int i;
192   unsigned int i1;
193     
194   /* First process options, they might be necessary for opening files
195      (especially include statements). */  
196   i  = 0;
197   if (cppopts) {
198     while(cppopts[i]) {
199       if (strstr(cppopts[i],"-I") == cppopts[i])
200         add_include(cppopts[i]+2);
201       if (strstr(cppopts[i],"-D") == cppopts[i])
202       {
203         /* If the option contains a =, split it into name and value. */
204         ptr = strchr(cppopts[i], '=');
205         if (ptr)
206         {
207           buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
208           add_define(buf, ptr + 1);
209           sfree(buf);
210         }
211         else
212         {
213           add_define(cppopts[i] + 2, NULL);
214         }
215       }
216       i++;
217     }
218   }
219   if (debug)
220     fprintf(debug,"GMXCPP: added %d command line arguments\n",i);
221   
222   snew(cpp,1);
223   *handle      = cpp;
224   cpp->fn      = NULL;
225   /* Find the file. First check whether it is in the current directory. */
226   if (gmx_fexist(filenm))
227   {
228     cpp->fn = strdup(filenm);
229   }
230   else
231   {
232     /* If not, check all the paths given with -I. */
233     for (i = 0; i < nincl; ++i)
234     {
235       snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
236       sprintf(buf, "%s/%s", incl[i], filenm);
237       if (gmx_fexist(buf))
238       {
239           cpp->fn = buf;
240         break;
241       }
242       sfree(buf);
243     }
244     /* If still not found, check the Gromacs library search path. */
245     if (!cpp->fn)
246     {
247       cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
248     }
249   }
250   if (!cpp->fn)
251   {
252     gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
253   }
254   if (NULL != debug) {
255     fprintf(debug,"GMXCPP: cpp file open %s\n",cpp->fn);
256   }
257   /* If the file name has a path component, we need to change to that
258    * directory. Note that we - just as C - always use UNIX path separators
259    * internally in include file names.
260    */
261   ptr  = strrchr(cpp->fn, '/');
262   ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
263     
264   if (ptr == NULL || (ptr2 != NULL && ptr2 > ptr))
265   {
266       ptr = ptr2;
267   }
268   if(ptr==NULL)
269   {
270     cpp->path = NULL;
271     cpp->cwd  = NULL;
272   }
273   else
274   {
275     cpp->path = cpp->fn;
276     *ptr      = '\0';
277     cpp->fn   = strdup(ptr+1);
278     snew(cpp->cwd,STRLEN);
279       
280 #ifdef GMX_NATIVE_WINDOWS
281       pdum=_getcwd(cpp->cwd,STRLEN);
282       _chdir(cpp->path);
283 #else
284       pdum=getcwd(cpp->cwd,STRLEN);
285       if (NULL != debug) {
286         fprintf(debug,"GMXCPP: cwd %s\n",cpp->cwd);
287       }
288       if (-1 == chdir(cpp->path))
289         gmx_fatal(FARGS,"Can not chdir to %s when processing topology. Reason: %s",
290                   cpp->path,strerror(errno));
291
292 #endif
293       
294     if (NULL != debug)
295       fprintf(debug,"GMXCPP: chdir to %s\n",cpp->path);
296   }
297   cpp->line_len= 0;
298   cpp->line    = NULL;
299   cpp->line_nr = 0;
300   cpp->nifdef  = 0;
301   cpp->ifdefs  = NULL;
302   cpp->child   = NULL;
303   cpp->parent  = NULL;
304   if (cpp->fp == NULL) {
305     if (NULL != debug) {
306       fprintf(debug,"GMXCPP: opening file %s\n",cpp->fn);
307     }
308     cpp->fp = fopen(cpp->fn, "r");
309   }
310   if (cpp->fp == NULL) {
311     switch(errno) {
312     case EINVAL:
313     default:
314       return eCPP_UNKNOWN;
315     }
316   }
317   return eCPP_OK;
318 }
319
320 static int
321 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
322 {
323   gmx_cpp_t handle = (gmx_cpp_t)*handlep;
324   int  i,i0,len,status;
325   unsigned int i1;
326   char *inc_fn,*name;
327   const char *ptr;
328   int  bIfdef,bIfndef;
329
330   /* #ifdef or ifndef statement */
331   bIfdef  = (strcmp(dname,"ifdef") == 0);
332   bIfndef = (strcmp(dname,"ifndef") == 0);
333   if (bIfdef || bIfndef) {
334     if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE)) {
335       handle->nifdef++;
336       srenew(handle->ifdefs,handle->nifdef);
337       handle->ifdefs[handle->nifdef-1] = eifIGNORE;
338     }
339     else {
340       snew(name,strlen(dval)+1);
341       sscanf(dval,"%s",name);
342       for(i=0; (i<ndef); i++) 
343         if (strcmp(defs[i].name,name) == 0) 
344           break;
345       handle->nifdef++;
346       srenew(handle->ifdefs,handle->nifdef);
347       if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef))) 
348         handle->ifdefs[handle->nifdef-1] = eifTRUE;
349       else
350         handle->ifdefs[handle->nifdef-1] = eifFALSE;
351       sfree(name);
352     }
353     return eCPP_OK;
354   }
355   
356   /* #else statement */
357   if (strcmp(dname,"else") == 0) {
358     if (handle->nifdef <= 0)
359       return eCPP_SYNTAX;
360     if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
361       handle->ifdefs[handle->nifdef-1] = eifFALSE;
362     else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
363       handle->ifdefs[handle->nifdef-1] = eifTRUE;
364     return eCPP_OK;
365   }
366   
367   /* #endif statement */
368   if (strcmp(dname,"endif") == 0) {
369     if (handle->nifdef <= 0)
370       return eCPP_SYNTAX;
371     handle->nifdef--;
372     return eCPP_OK;
373   }
374
375   /* Check whether we're not ifdeffed out. The order of this statement
376      is important. It has to come after #ifdef, #else and #endif, but
377      anything else should be ignored. */
378   if (is_ifdeffed_out(handle)) {
379     return eCPP_OK;
380   }
381   
382   /* Check for include statements */
383   if (strcmp(dname,"include") == 0) {
384     len = -1;
385     i0  = 0;
386     for(i1=0; (i1<strlen(dval)); i1++) {
387       if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))  {
388         if (len == -1) {
389           i0 = i1+1;
390           len = 0;
391         }
392         else
393           break;
394       }
395       else if (len >= 0)
396         len++;
397     }
398     if (len == -1) {
399       return eCPP_SYNTAX;
400     }
401     snew(inc_fn,len+1);
402     strncpy(inc_fn,dval+i0,len);
403     inc_fn[len] = '\0';
404     
405     if (debug)
406       fprintf(debug,"Going to open include file '%s' i0 = %d, strlen = %d\n",
407               inc_fn,i0,len);
408     /* Open include file and store it as a child in the handle structure */
409     status = cpp_open_file(inc_fn,&(handle->child),NULL);
410     sfree(inc_fn);
411     if (status != eCPP_OK) {
412       handle->child = NULL;
413       return status;
414     }
415     /* Make a linked list of open files and move on to the include file */
416     handle->child->parent = handle;
417     *handlep = handle->child;
418     handle = *handlep;
419     return eCPP_OK;
420   }
421   
422   /* #define statement */
423   if (strcmp(dname,"define") == 0) {
424     /* Split it into name and value. */
425     ptr = dval;
426     while ((*ptr != '\0') && !isspace(*ptr))
427       ptr++;
428     name = gmx_strndup(dval, ptr - dval);
429
430     while ((*ptr != '\0') && isspace(*ptr))
431       ptr++;
432
433     add_define(name, ptr);
434     sfree(name);
435     return eCPP_OK;
436   }
437   
438   /* #undef statement */
439   if (strcmp(dname,"undef") == 0) {
440     snew(name,strlen(dval)+1);
441     sscanf(dval,"%s",name);
442     for(i=0; (i<ndef); i++) {
443       if (strcmp(defs[i].name,name) == 0) {
444         sfree(defs[i].name);
445         sfree(defs[i].def);
446         break;
447       }
448     }
449     sfree(name);
450     for( ; (i<ndef-1); i++) {
451       defs[i].name = defs[i+1].name;
452       defs[i].def  = defs[i+1].def;
453     }
454     ndef--;
455     
456     return eCPP_OK;
457   }
458
459   /* If we haven't matched anything, this is an unknown directive */
460   return eCPP_SYNTAX;
461 }
462
463 /* Return one whole line from the file into buf which holds at most n
464    characters, for subsequent processing. Returns integer status. This
465    routine also does all the "intelligent" work like processing cpp
466    directives and so on. Note that often the routine is called
467    recursively and no cpp directives are printed. */
468 int cpp_read_line(gmx_cpp_t *handlep,int n,char buf[])
469 {
470   gmx_cpp_t handle = (gmx_cpp_t)*handlep;
471   int  i,nn,len,status;
472   const char *ptr, *ptr2;
473   char *name;
474   char *dname, *dval;
475   gmx_bool bEOF;
476
477   if (!handle)
478     return eCPP_INVALID_HANDLE;
479   if (!handle->fp)
480     return eCPP_FILE_NOT_OPEN;
481
482   bEOF = feof(handle->fp);
483   if (!bEOF) {
484     /* Read the actual line now. */
485     if (fgets2(buf,n-1,handle->fp) == NULL) {
486       /* Recheck EOF, since we could have been at the end before
487        * the fgets2 call, but we need to read past the end to know.
488        */
489        bEOF = feof(handle->fp);
490        if (!bEOF) {
491          /* Something strange happened, fgets returned NULL,
492           * but we are not at EOF.
493           */
494          return eCPP_UNKNOWN;
495        }
496     }
497   }
498
499   if (bEOF) {
500     if (handle->parent == NULL) {
501       return eCPP_EOF;
502     }
503     cpp_close_file(handlep);
504     *handlep = handle->parent;
505     handle->child = NULL;
506     return cpp_read_line(handlep,n,buf);
507   }
508   else {
509     if (n > handle->line_len) {
510       handle->line_len = n;
511       srenew(handle->line,n);
512     }
513     strcpy(handle->line,buf);
514     handle->line_nr++;
515   }
516   /* Now we've read a line! */
517   if (debug) 
518     fprintf(debug,"%s : %4d : %s\n",handle->fn,handle->line_nr,buf);
519
520   /* Process directives if this line contains one */
521   if (find_directive(buf, &dname, &dval))
522   {
523       status = process_directive(handlep, dname, dval);
524       if (status != eCPP_OK)
525           return status;
526         /* Don't print lines with directives, go on to the next */
527       return cpp_read_line(handlep,n,buf);
528   }
529
530   /* Check whether we're not ifdeffed out. The order of this statement
531      is important. It has to come after #ifdef, #else and #endif, but
532      anything else should be ignored. */
533   if (is_ifdeffed_out(handle)) {
534     return cpp_read_line(handlep,n,buf);
535   }
536   
537   /* Check whether we have any defines that need to be replaced. Note
538      that we have to use a best fit algorithm, rather than first come
539      first go. We do this by sorting the defines on length first, and
540      then on alphabetical order. */
541   for(i=0; (i<ndef); i++) {
542     if (defs[i].def) {
543       nn  = 0;
544       ptr = buf;
545       while ((ptr = strstrw(ptr,defs[i].name)) != NULL) {
546         nn++;
547         ptr += strlen(defs[i].name);
548       }
549       if (nn > 0) {
550         len = strlen(buf) + nn*max(4,4+strlen(defs[i].def)-strlen(defs[i].name));
551         snew(name,len);
552         ptr = buf;
553         while ((ptr2 = strstrw(ptr,defs[i].name)) != NULL) {
554           strncat(name,ptr,(int)(ptr2-ptr));
555           strcat(name,defs[i].def);
556           ptr = ptr2 + strlen(defs[i].name);
557         }
558         strcat(name,ptr);
559         strcpy(buf,name);
560         sfree(name);
561       }
562     }
563   }
564   
565   return eCPP_OK;
566 }
567
568 char *cpp_cur_file(const gmx_cpp_t *handlep)
569 {
570   return (*handlep)->fn;
571 }
572
573 int cpp_cur_linenr(const gmx_cpp_t *handlep)
574 {
575   return (*handlep)->line_nr;
576 }
577
578 /* Close the file! Return integer status. */
579 int cpp_close_file(gmx_cpp_t *handlep)
580 {
581   int i;
582   gmx_cpp_t handle = (gmx_cpp_t)*handlep;
583   
584   if (!handle)
585     return eCPP_INVALID_HANDLE;
586   if (!handle->fp)
587     return eCPP_FILE_NOT_OPEN;
588   if (debug)
589     fprintf(debug,"GMXCPP: closing file %s\n",handle->fn);
590   fclose(handle->fp);
591   if (NULL != handle->cwd) {
592     if (NULL != debug)
593       fprintf(debug,"GMXCPP: chdir to %s\n",handle->cwd);
594 #ifdef GMX_NATIVE_WINDOWS
595       _chdir(handle->cwd);
596 #else
597       if (-1 == chdir(handle->cwd))
598         gmx_fatal(FARGS,"Can not chdir to %s when processing topology: %s",
599                   handle->cwd,strerror(errno));
600 #endif
601   }
602   
603   if (0)
604     switch(errno) {
605   case 0:
606     break;
607   case ENOENT:
608     return eCPP_FILE_NOT_FOUND;
609   case EBADF:
610     return eCPP_FILE_NOT_OPEN;
611   case EINTR:
612     return eCPP_INTERRUPT;
613   default:
614     if (debug)
615       fprintf(debug,"Strange stuff closing file, errno = %d",errno);
616     return eCPP_UNKNOWN;
617   }
618   handle->fp = NULL;
619   handle->line_nr = 0;
620   if (NULL != handle->fn) {
621     sfree(handle->fn);
622     handle->fn = NULL;
623   }
624   if (NULL != handle->line) {
625     sfree(handle->line);
626     handle->line = NULL;
627   }
628   if (NULL != handle->ifdefs) 
629     sfree(handle->ifdefs);
630   handle->nifdef = 0;
631   if (NULL != handle->path)
632     sfree(handle->path);
633   if (NULL != handle->cwd)
634     sfree(handle->cwd);
635     
636   return eCPP_OK;
637 }
638
639 /* Return a string containing the error message coresponding to status
640    variable */
641 char *cpp_error(gmx_cpp_t *handlep,int status)
642 {
643   char buf[256];
644   const char *ecpp[] = {
645     "OK", "File not found", "End of file", "Syntax error", "Interrupted",
646     "Invalid file handle", 
647     "File not open", "Unknown error", "Error status out of range"
648   };
649   gmx_cpp_t handle = (gmx_cpp_t)*handlep;
650   
651   if (!handle)
652     return (char *)ecpp[eCPP_INVALID_HANDLE];
653     
654   if ((status < 0) || (status >= eCPP_NR))
655     status = eCPP_NR;
656   
657   sprintf(buf,"%s - File %s, line %d\nLast line read:\n'%s'",
658           ecpp[status],
659           (handle && handle->fn) ? handle->fn : "unknown",
660           (handle) ? handle->line_nr : -1,
661           handle->line ? handle->line : "");
662   
663   return strdup(buf);
664 }