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