4bac41ea0b6930d22b726cc9479ef7769e36d058
[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         if (debug)
216         {
217             fprintf(debug, "Overriding define %s\n", name);
218         }
219         sfree(defs[i].def);
220     }
221     if (value && strlen(value) > 0)
222     {
223         defs[i].def  = gmx_strdup(value);
224     }
225     else
226     {
227         defs[i].def  = nullptr;
228     }
229 }
230
231 static void done_defines()
232 {
233     int i;
234     for (i = 0; (i < ndef); i++)
235     {
236         sfree(defs[i].name);
237         sfree(defs[i].def);
238     }
239     sfree(defs);
240     defs = nullptr;
241     ndef = 0;
242 }
243
244 /* Open the file to be processed. The handle variable holds internal
245    info for the cpp emulator. Return integer status */
246 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
247 {
248     gmx_cpp_t    cpp;
249     char        *buf;
250     char        *ptr, *ptr2;
251     int          i;
252
253     /* First process options, they might be necessary for opening files
254        (especially include statements). */
255     i  = 0;
256     if (cppopts)
257     {
258         while (cppopts[i])
259         {
260             if (strstr(cppopts[i], "-I") == cppopts[i])
261             {
262                 add_include(cppopts[i]+2);
263             }
264             if (strstr(cppopts[i], "-D") == cppopts[i])
265             {
266                 /* If the option contains a =, split it into name and value. */
267                 ptr = strchr(cppopts[i], '=');
268                 if (ptr)
269                 {
270                     buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
271                     add_define(buf, ptr + 1);
272                     sfree(buf);
273                 }
274                 else
275                 {
276                     add_define(cppopts[i] + 2, nullptr);
277                 }
278             }
279             i++;
280         }
281     }
282     if (debug)
283     {
284         fprintf(debug, "GMXCPP: added %d command line arguments\n", i);
285     }
286
287     snew(cpp, 1);
288     *handle      = cpp;
289     cpp->fn      = nullptr;
290     /* Find the file. First check whether it is in the current directory. */
291     if (gmx_fexist(filenm))
292     {
293         cpp->fn = gmx_strdup(filenm);
294     }
295     else
296     {
297         /* If not, check all the paths given with -I. */
298         for (i = 0; i < nincl; ++i)
299         {
300             snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
301             sprintf(buf, "%s/%s", incl[i], filenm);
302             if (gmx_fexist(buf))
303             {
304                 cpp->fn = buf;
305                 break;
306             }
307             sfree(buf);
308         }
309         /* If still not found, check the Gromacs library search path. */
310         if (!cpp->fn)
311         {
312             cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
313         }
314     }
315     if (!cpp->fn)
316     {
317         gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
318     }
319     if (nullptr != debug)
320     {
321         fprintf(debug, "GMXCPP: cpp file open %s\n", cpp->fn);
322     }
323     /* If the file name has a path component, we need to change to that
324      * directory. Note that we - just as C - always use UNIX path separators
325      * internally in include file names.
326      */
327     ptr  = strrchr(cpp->fn, '/');
328     ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
329
330     if (ptr == nullptr || (ptr2 != nullptr && ptr2 > ptr))
331     {
332         ptr = ptr2;
333     }
334     if (ptr == nullptr)
335     {
336         cpp->path = nullptr;
337         cpp->cwd  = nullptr;
338     }
339     else
340     {
341         cpp->path = cpp->fn;
342         *ptr      = '\0';
343         cpp->fn   = gmx_strdup(ptr+1);
344         snew(cpp->cwd, STRLEN);
345
346         gmx_getcwd(cpp->cwd, STRLEN);
347         if (nullptr != debug)
348         {
349             fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
350         }
351         gmx_chdir(cpp->path);
352
353         if (nullptr != debug)
354         {
355             fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
356         }
357     }
358     cpp->line_len = 0;
359     cpp->line     = nullptr;
360     cpp->line_nr  = 0;
361     cpp->nifdef   = 0;
362     cpp->ifdefs   = nullptr;
363     cpp->child    = nullptr;
364     cpp->parent   = nullptr;
365     if (cpp->fp == nullptr)
366     {
367         if (nullptr != debug)
368         {
369             fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
370         }
371         cpp->fp = fopen(cpp->fn, "r");
372     }
373     if (cpp->fp == nullptr)
374     {
375         switch (errno)
376         {
377             case EINVAL:
378             default:
379                 return eCPP_UNKNOWN;
380         }
381     }
382     return eCPP_OK;
383 }
384
385 /* Note that dval might be null, e.g. when handling a line like '#define */
386 static int
387 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
388 {
389     gmx_cpp_t    handle = (gmx_cpp_t)*handlep;
390     int          i, i0, len, status;
391     unsigned int i1;
392     char        *inc_fn, *name;
393     const char  *ptr;
394     int          bIfdef, bIfndef;
395
396     /* #ifdef or ifndef statement */
397     bIfdef  = (strcmp(dname, "ifdef") == 0);
398     bIfndef = (strcmp(dname, "ifndef") == 0);
399     if (bIfdef || bIfndef)
400     {
401         GMX_RELEASE_ASSERT(dval, "#ifdef/#ifndef requires an argument");
402         if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
403         {
404             handle->nifdef++;
405             srenew(handle->ifdefs, handle->nifdef);
406             handle->ifdefs[handle->nifdef-1] = eifIGNORE;
407         }
408         else
409         {
410             // A bare '#ifdef' or '#ifndef' is invalid
411             if (dval == nullptr)
412             {
413                 return eCPP_SYNTAX;
414             }
415             snew(name, strlen(dval)+1);
416             sscanf(dval, "%s", name);
417             for (i = 0; (i < ndef); i++)
418             {
419                 if (strcmp(defs[i].name, name) == 0)
420                 {
421                     break;
422                 }
423             }
424             handle->nifdef++;
425             srenew(handle->ifdefs, handle->nifdef);
426             if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
427             {
428                 handle->ifdefs[handle->nifdef-1] = eifTRUE;
429             }
430             else
431             {
432                 handle->ifdefs[handle->nifdef-1] = eifFALSE;
433             }
434             sfree(name);
435         }
436         return eCPP_OK;
437     }
438
439     /* #else statement */
440     if (strcmp(dname, "else") == 0)
441     {
442         if (handle->nifdef <= 0)
443         {
444             return eCPP_SYNTAX;
445         }
446         if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
447         {
448             handle->ifdefs[handle->nifdef-1] = eifFALSE;
449         }
450         else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
451         {
452             handle->ifdefs[handle->nifdef-1] = eifTRUE;
453         }
454         return eCPP_OK;
455     }
456
457     /* #endif statement */
458     if (strcmp(dname, "endif") == 0)
459     {
460         if (handle->nifdef <= 0)
461         {
462             return eCPP_SYNTAX;
463         }
464         handle->nifdef--;
465         return eCPP_OK;
466     }
467
468     /* Check whether we're not ifdeffed out. The order of this statement
469        is important. It has to come after #ifdef, #else and #endif, but
470        anything else should be ignored. */
471     if (is_ifdeffed_out(handle))
472     {
473         return eCPP_OK;
474     }
475
476     /* Check for include statements */
477     if (strcmp(dname, "include") == 0)
478     {
479         GMX_RELEASE_ASSERT(dval, "#include requires an argument");
480         len = -1;
481         i0  = 0;
482         // A bare '#include' is an invalid line
483         if (dval == nullptr)
484         {
485             return eCPP_SYNTAX;
486         }
487         for (i1 = 0; (i1 < strlen(dval)); i1++)
488         {
489             if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
490             {
491                 if (len == -1)
492                 {
493                     i0  = i1+1;
494                     len = 0;
495                 }
496                 else
497                 {
498                     break;
499                 }
500             }
501             else if (len >= 0)
502             {
503                 len++;
504             }
505         }
506         if (len == -1)
507         {
508             return eCPP_SYNTAX;
509         }
510         snew(inc_fn, len+1);
511         strncpy(inc_fn, dval+i0, len);
512         inc_fn[len] = '\0';
513
514         if (debug)
515         {
516             fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
517                     inc_fn, i0, len);
518         }
519         /* Open include file and store it as a child in the handle structure */
520         status = cpp_open_file(inc_fn, &(handle->child), nullptr);
521         sfree(inc_fn);
522         if (status != eCPP_OK)
523         {
524             handle->child = nullptr;
525             return status;
526         }
527         /* Make a linked list of open files and move on to the include file */
528         handle->child->parent = handle;
529         *handlep              = handle->child;
530         return eCPP_OK;
531     }
532
533     /* #define statement */
534     if (strcmp(dname, "define") == 0)
535     {
536         // A bare '#define' is an invalid line
537         if (dval == nullptr)
538         {
539             return eCPP_SYNTAX;
540         }
541         /* Split it into name and value. */
542         ptr = dval;
543         while ((*ptr != '\0') && !isspace(*ptr))
544         {
545             ptr++;
546         }
547         name = gmx_strndup(dval, ptr - dval);
548
549         while ((*ptr != '\0') && isspace(*ptr))
550         {
551             ptr++;
552         }
553
554         add_define(name, ptr);
555         sfree(name);
556         return eCPP_OK;
557     }
558
559     /* #undef statement */
560     if (strcmp(dname, "undef") == 0)
561     {
562         // A bare '#undef' is an invalid line
563         if (dval == nullptr)
564         {
565             return eCPP_SYNTAX;
566         }
567         snew(name, strlen(dval)+1);
568         sscanf(dval, "%s", name);
569         for (i = 0; (i < ndef); i++)
570         {
571             if (strcmp(defs[i].name, name) == 0)
572             {
573                 sfree(defs[i].name);
574                 sfree(defs[i].def);
575                 break;
576             }
577         }
578         sfree(name);
579         for (; (i < ndef-1); i++)
580         {
581             defs[i].name = defs[i+1].name;
582             defs[i].def  = defs[i+1].def;
583         }
584         ndef--;
585
586         return eCPP_OK;
587     }
588
589     /* If we haven't matched anything, this is an unknown directive */
590     return eCPP_SYNTAX;
591 }
592
593 /* Return one whole line from the file into buf which holds at most n
594    characters, for subsequent processing. Returns integer status. This
595    routine also does all the "intelligent" work like processing cpp
596    directives and so on. Note that often the routine is called
597    recursively and no cpp directives are printed. */
598 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
599 {
600     gmx_cpp_t   handle = (gmx_cpp_t)*handlep;
601     int         i, nn, len, status;
602     const char *ptr, *ptr2;
603     char       *name;
604     char       *dname, *dval;
605     bool        bEOF;
606
607     if (!handle)
608     {
609         return eCPP_INVALID_HANDLE;
610     }
611     if (!handle->fp)
612     {
613         return eCPP_FILE_NOT_OPEN;
614     }
615
616     bEOF = feof(handle->fp);
617     if (!bEOF)
618     {
619         /* Read the actual line now. */
620         if (fgets2(buf, n-1, handle->fp) == nullptr)
621         {
622             /* Recheck EOF, since we could have been at the end before
623              * the fgets2 call, but we need to read past the end to know.
624              */
625             bEOF = feof(handle->fp);
626             if (!bEOF)
627             {
628                 /* Something strange happened, fgets returned NULL,
629                  * but we are not at EOF.
630                  */
631                 return eCPP_UNKNOWN;
632             }
633         }
634     }
635
636     if (bEOF)
637     {
638         if (handle->parent == nullptr)
639         {
640             return eCPP_EOF;
641         }
642         cpp_close_file(handlep);
643         *handlep      = handle->parent;
644         handle->child = nullptr;
645         return cpp_read_line(handlep, n, buf);
646     }
647     else
648     {
649         if (n > handle->line_len)
650         {
651             handle->line_len = n;
652             srenew(handle->line, n);
653         }
654         strcpy(handle->line, buf);
655         handle->line_nr++;
656     }
657     /* Now we've read a line! */
658     if (debug)
659     {
660         fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
661     }
662
663     /* Process directives if this line contains one */
664     if (find_directive(buf, &dname, &dval))
665     {
666         status = process_directive(handlep, dname, dval);
667         if (status != eCPP_OK)
668         {
669             return status;
670         }
671         /* Don't print lines with directives, go on to the next */
672         return cpp_read_line(handlep, n, buf);
673     }
674
675     /* Check whether we're not ifdeffed out. The order of this statement
676        is important. It has to come after #ifdef, #else and #endif, but
677        anything else should be ignored. */
678     if (is_ifdeffed_out(handle))
679     {
680         return cpp_read_line(handlep, n, buf);
681     }
682
683     /* Check whether we have any defines that need to be replaced. Note
684        that we have to use a best fit algorithm, rather than first come
685        first go. We do this by sorting the defines on length first, and
686        then on alphabetical order. */
687     for (i = 0; (i < ndef); i++)
688     {
689         if (defs[i].def)
690         {
691             nn  = 0;
692             ptr = buf;
693             while ((ptr = strstrw(ptr, defs[i].name)) != nullptr)
694             {
695                 nn++;
696                 ptr += strlen(defs[i].name);
697             }
698             if (nn > 0)
699             {
700                 size_t four = 4;
701
702                 len = strlen(buf) + nn*std::max(four, four+strlen(defs[i].def)-strlen(defs[i].name));
703                 snew(name, len);
704                 ptr = buf;
705                 while ((ptr2 = strstrw(ptr, defs[i].name)) != nullptr)
706                 {
707                     strncat(name, ptr, (int)(ptr2-ptr));
708                     strcat(name, defs[i].def);
709                     ptr = ptr2 + strlen(defs[i].name);
710                 }
711                 strcat(name, ptr);
712                 strcpy(buf, name);
713                 sfree(name);
714             }
715         }
716     }
717
718     return eCPP_OK;
719 }
720
721 char *cpp_cur_file(const gmx_cpp_t *handlep)
722 {
723     return (*handlep)->fn;
724 }
725
726 int cpp_cur_linenr(const gmx_cpp_t *handlep)
727 {
728     return (*handlep)->line_nr;
729 }
730
731 /* Close the file! Return integer status. */
732 int cpp_close_file(gmx_cpp_t *handlep)
733 {
734     gmx_cpp_t handle = (gmx_cpp_t)*handlep;
735
736     if (!handle)
737     {
738         return eCPP_INVALID_HANDLE;
739     }
740     if (!handle->fp)
741     {
742         return eCPP_FILE_NOT_OPEN;
743     }
744     if (debug)
745     {
746         fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
747     }
748     fclose(handle->fp);
749     if (nullptr != handle->cwd)
750     {
751         if (nullptr != debug)
752         {
753             fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
754         }
755         gmx_chdir(handle->cwd);
756     }
757
758     if (0)
759     {
760         switch (errno)
761         {
762             case 0:
763                 break;
764             case ENOENT:
765                 return eCPP_FILE_NOT_FOUND;
766             case EBADF:
767                 return eCPP_FILE_NOT_OPEN;
768             case EINTR:
769                 return eCPP_INTERRUPT;
770             default:
771                 if (debug)
772                 {
773                     fprintf(debug, "Strange stuff closing file, errno = %d", errno);
774                 }
775                 return eCPP_UNKNOWN;
776         }
777     }
778     handle->fp      = nullptr;
779     handle->line_nr = 0;
780     if (nullptr != handle->fn)
781     {
782         sfree(handle->fn);
783         handle->fn = nullptr;
784     }
785     if (nullptr != handle->line)
786     {
787         sfree(handle->line);
788         handle->line = nullptr;
789     }
790     if (nullptr != handle->ifdefs)
791     {
792         sfree(handle->ifdefs);
793     }
794     handle->nifdef = 0;
795     if (nullptr != handle->path)
796     {
797         sfree(handle->path);
798     }
799     if (nullptr != handle->cwd)
800     {
801         sfree(handle->cwd);
802     }
803
804     return eCPP_OK;
805 }
806
807 void cpp_done()
808 {
809     done_includes();
810     done_defines();
811 }
812
813 /* Return a string containing the error message coresponding to status
814    variable */
815 char *cpp_error(gmx_cpp_t *handlep, int status)
816 {
817     char        buf[256];
818     const char *ecpp[] = {
819         "OK", "File not found", "End of file", "Syntax error", "Interrupted",
820         "Invalid file handle",
821         "File not open", "Unknown error", "Error status out of range"
822     };
823     gmx_cpp_t   handle = (gmx_cpp_t)*handlep;
824
825     if (!handle)
826     {
827         return (char *)ecpp[eCPP_INVALID_HANDLE];
828     }
829
830     if ((status < 0) || (status >= eCPP_NR))
831     {
832         status = eCPP_NR;
833     }
834
835     sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
836             ecpp[status],
837             (handle && handle->fn) ? handle->fn : "unknown",
838             (handle) ? handle->line_nr : -1,
839             handle->line ? handle->line : "");
840
841     return gmx_strdup(buf);
842 }