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