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