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