Code beautification with uncrustify
[alexxy/gromacs.git] / src / gromacs / gmxlib / gmxcpp.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
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 "string2.h"
49 #include "smalloc.h"
50 #include "futil.h"
51 #include "macros.h"
52 #include "gmx_fatal.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] = strdup(include);
171     }
172 }
173
174 static void add_define(const char *name, const char *value)
175 {
176     int  i;
177
178     for (i = 0; (i < ndef); i++)
179     {
180         if (strcmp(defs[i].name, name) == 0)
181         {
182             break;
183         }
184     }
185     if (i == ndef)
186     {
187         ndef++;
188         srenew(defs, ndef);
189         i            = ndef - 1;
190         defs[i].name = strdup(name);
191     }
192     else if (defs[i].def)
193     {
194         if (debug)
195         {
196             fprintf(debug, "Overriding define %s\n", name);
197         }
198         sfree(defs[i].def);
199     }
200     if (value && strlen(value) > 0)
201     {
202         defs[i].def  = strdup(value);
203     }
204     else
205     {
206         defs[i].def  = NULL;
207     }
208 }
209
210 /* Open the file to be processed. The handle variable holds internal
211    info for the cpp emulator. Return integer status */
212 int cpp_open_file(const char *filenm, gmx_cpp_t *handle, char **cppopts)
213 {
214     gmx_cpp_t    cpp;
215     char        *buf, *pdum;
216     char        *ptr, *ptr2;
217     int          i;
218     unsigned int i1;
219
220     /* First process options, they might be necessary for opening files
221        (especially include statements). */
222     i  = 0;
223     if (cppopts)
224     {
225         while (cppopts[i])
226         {
227             if (strstr(cppopts[i], "-I") == cppopts[i])
228             {
229                 add_include(cppopts[i]+2);
230             }
231             if (strstr(cppopts[i], "-D") == cppopts[i])
232             {
233                 /* If the option contains a =, split it into name and value. */
234                 ptr = strchr(cppopts[i], '=');
235                 if (ptr)
236                 {
237                     buf = gmx_strndup(cppopts[i] + 2, ptr - cppopts[i] - 2);
238                     add_define(buf, ptr + 1);
239                     sfree(buf);
240                 }
241                 else
242                 {
243                     add_define(cppopts[i] + 2, NULL);
244                 }
245             }
246             i++;
247         }
248     }
249     if (debug)
250     {
251         fprintf(debug, "GMXCPP: added %d command line arguments\n", i);
252     }
253
254     snew(cpp, 1);
255     *handle      = cpp;
256     cpp->fn      = NULL;
257     /* Find the file. First check whether it is in the current directory. */
258     if (gmx_fexist(filenm))
259     {
260         cpp->fn = strdup(filenm);
261     }
262     else
263     {
264         /* If not, check all the paths given with -I. */
265         for (i = 0; i < nincl; ++i)
266         {
267             snew(buf, strlen(incl[i]) + strlen(filenm) + 2);
268             sprintf(buf, "%s/%s", incl[i], filenm);
269             if (gmx_fexist(buf))
270             {
271                 cpp->fn = buf;
272                 break;
273             }
274             sfree(buf);
275         }
276         /* If still not found, check the Gromacs library search path. */
277         if (!cpp->fn)
278         {
279             cpp->fn = low_gmxlibfn(filenm, FALSE, FALSE);
280         }
281     }
282     if (!cpp->fn)
283     {
284         gmx_fatal(FARGS, "Topology include file \"%s\" not found", filenm);
285     }
286     if (NULL != debug)
287     {
288         fprintf(debug, "GMXCPP: cpp file open %s\n", cpp->fn);
289     }
290     /* If the file name has a path component, we need to change to that
291      * directory. Note that we - just as C - always use UNIX path separators
292      * internally in include file names.
293      */
294     ptr  = strrchr(cpp->fn, '/');
295     ptr2 = strrchr(cpp->fn, DIR_SEPARATOR);
296
297     if (ptr == NULL || (ptr2 != NULL && ptr2 > ptr))
298     {
299         ptr = ptr2;
300     }
301     if (ptr == NULL)
302     {
303         cpp->path = NULL;
304         cpp->cwd  = NULL;
305     }
306     else
307     {
308         cpp->path = cpp->fn;
309         *ptr      = '\0';
310         cpp->fn   = strdup(ptr+1);
311         snew(cpp->cwd, STRLEN);
312
313         gmx_getcwd(cpp->cwd, STRLEN);
314         if (NULL != debug)
315         {
316             fprintf(debug, "GMXCPP: cwd %s\n", cpp->cwd);
317         }
318         gmx_chdir(cpp->path);
319
320         if (NULL != debug)
321         {
322             fprintf(debug, "GMXCPP: chdir to %s\n", cpp->path);
323         }
324     }
325     cpp->line_len = 0;
326     cpp->line     = NULL;
327     cpp->line_nr  = 0;
328     cpp->nifdef   = 0;
329     cpp->ifdefs   = NULL;
330     cpp->child    = NULL;
331     cpp->parent   = NULL;
332     if (cpp->fp == NULL)
333     {
334         if (NULL != debug)
335         {
336             fprintf(debug, "GMXCPP: opening file %s\n", cpp->fn);
337         }
338         cpp->fp = fopen(cpp->fn, "r");
339     }
340     if (cpp->fp == NULL)
341     {
342         switch (errno)
343         {
344             case EINVAL:
345             default:
346                 return eCPP_UNKNOWN;
347         }
348     }
349     return eCPP_OK;
350 }
351
352 static int
353 process_directive(gmx_cpp_t *handlep, const char *dname, const char *dval)
354 {
355     gmx_cpp_t    handle = (gmx_cpp_t)*handlep;
356     int          i, i0, len, status;
357     unsigned int i1;
358     char        *inc_fn, *name;
359     const char  *ptr;
360     int          bIfdef, bIfndef;
361
362     /* #ifdef or ifndef statement */
363     bIfdef  = (strcmp(dname, "ifdef") == 0);
364     bIfndef = (strcmp(dname, "ifndef") == 0);
365     if (bIfdef || bIfndef)
366     {
367         if ((handle->nifdef > 0) && (handle->ifdefs[handle->nifdef-1] != eifTRUE))
368         {
369             handle->nifdef++;
370             srenew(handle->ifdefs, handle->nifdef);
371             handle->ifdefs[handle->nifdef-1] = eifIGNORE;
372         }
373         else
374         {
375             snew(name, strlen(dval)+1);
376             sscanf(dval, "%s", name);
377             for (i = 0; (i < ndef); i++)
378             {
379                 if (strcmp(defs[i].name, name) == 0)
380                 {
381                     break;
382                 }
383             }
384             handle->nifdef++;
385             srenew(handle->ifdefs, handle->nifdef);
386             if ((bIfdef && (i < ndef)) || (bIfndef && (i == ndef)))
387             {
388                 handle->ifdefs[handle->nifdef-1] = eifTRUE;
389             }
390             else
391             {
392                 handle->ifdefs[handle->nifdef-1] = eifFALSE;
393             }
394             sfree(name);
395         }
396         return eCPP_OK;
397     }
398
399     /* #else statement */
400     if (strcmp(dname, "else") == 0)
401     {
402         if (handle->nifdef <= 0)
403         {
404             return eCPP_SYNTAX;
405         }
406         if (handle->ifdefs[handle->nifdef-1] == eifTRUE)
407         {
408             handle->ifdefs[handle->nifdef-1] = eifFALSE;
409         }
410         else if (handle->ifdefs[handle->nifdef-1] == eifFALSE)
411         {
412             handle->ifdefs[handle->nifdef-1] = eifTRUE;
413         }
414         return eCPP_OK;
415     }
416
417     /* #endif statement */
418     if (strcmp(dname, "endif") == 0)
419     {
420         if (handle->nifdef <= 0)
421         {
422             return eCPP_SYNTAX;
423         }
424         handle->nifdef--;
425         return eCPP_OK;
426     }
427
428     /* Check whether we're not ifdeffed out. The order of this statement
429        is important. It has to come after #ifdef, #else and #endif, but
430        anything else should be ignored. */
431     if (is_ifdeffed_out(handle))
432     {
433         return eCPP_OK;
434     }
435
436     /* Check for include statements */
437     if (strcmp(dname, "include") == 0)
438     {
439         len = -1;
440         i0  = 0;
441         for (i1 = 0; (i1 < strlen(dval)); i1++)
442         {
443             if ((dval[i1] == '"') || (dval[i1] == '<') || (dval[i1] == '>'))
444             {
445                 if (len == -1)
446                 {
447                     i0  = i1+1;
448                     len = 0;
449                 }
450                 else
451                 {
452                     break;
453                 }
454             }
455             else if (len >= 0)
456             {
457                 len++;
458             }
459         }
460         if (len == -1)
461         {
462             return eCPP_SYNTAX;
463         }
464         snew(inc_fn, len+1);
465         strncpy(inc_fn, dval+i0, len);
466         inc_fn[len] = '\0';
467
468         if (debug)
469         {
470             fprintf(debug, "Going to open include file '%s' i0 = %d, strlen = %d\n",
471                     inc_fn, i0, len);
472         }
473         /* Open include file and store it as a child in the handle structure */
474         status = cpp_open_file(inc_fn, &(handle->child), NULL);
475         sfree(inc_fn);
476         if (status != eCPP_OK)
477         {
478             handle->child = NULL;
479             return status;
480         }
481         /* Make a linked list of open files and move on to the include file */
482         handle->child->parent = handle;
483         *handlep              = handle->child;
484         handle                = *handlep;
485         return eCPP_OK;
486     }
487
488     /* #define statement */
489     if (strcmp(dname, "define") == 0)
490     {
491         /* Split it into name and value. */
492         ptr = dval;
493         while ((*ptr != '\0') && !isspace(*ptr))
494         {
495             ptr++;
496         }
497         name = gmx_strndup(dval, ptr - dval);
498
499         while ((*ptr != '\0') && isspace(*ptr))
500         {
501             ptr++;
502         }
503
504         add_define(name, ptr);
505         sfree(name);
506         return eCPP_OK;
507     }
508
509     /* #undef statement */
510     if (strcmp(dname, "undef") == 0)
511     {
512         snew(name, strlen(dval)+1);
513         sscanf(dval, "%s", name);
514         for (i = 0; (i < ndef); i++)
515         {
516             if (strcmp(defs[i].name, name) == 0)
517             {
518                 sfree(defs[i].name);
519                 sfree(defs[i].def);
520                 break;
521             }
522         }
523         sfree(name);
524         for (; (i < ndef-1); i++)
525         {
526             defs[i].name = defs[i+1].name;
527             defs[i].def  = defs[i+1].def;
528         }
529         ndef--;
530
531         return eCPP_OK;
532     }
533
534     /* If we haven't matched anything, this is an unknown directive */
535     return eCPP_SYNTAX;
536 }
537
538 /* Return one whole line from the file into buf which holds at most n
539    characters, for subsequent processing. Returns integer status. This
540    routine also does all the "intelligent" work like processing cpp
541    directives and so on. Note that often the routine is called
542    recursively and no cpp directives are printed. */
543 int cpp_read_line(gmx_cpp_t *handlep, int n, char buf[])
544 {
545     gmx_cpp_t   handle = (gmx_cpp_t)*handlep;
546     int         i, nn, len, status;
547     const char *ptr, *ptr2;
548     char       *name;
549     char       *dname, *dval;
550     gmx_bool    bEOF;
551
552     if (!handle)
553     {
554         return eCPP_INVALID_HANDLE;
555     }
556     if (!handle->fp)
557     {
558         return eCPP_FILE_NOT_OPEN;
559     }
560
561     bEOF = feof(handle->fp);
562     if (!bEOF)
563     {
564         /* Read the actual line now. */
565         if (fgets2(buf, n-1, handle->fp) == NULL)
566         {
567             /* Recheck EOF, since we could have been at the end before
568              * the fgets2 call, but we need to read past the end to know.
569              */
570             bEOF = feof(handle->fp);
571             if (!bEOF)
572             {
573                 /* Something strange happened, fgets returned NULL,
574                  * but we are not at EOF.
575                  */
576                 return eCPP_UNKNOWN;
577             }
578         }
579     }
580
581     if (bEOF)
582     {
583         if (handle->parent == NULL)
584         {
585             return eCPP_EOF;
586         }
587         cpp_close_file(handlep);
588         *handlep      = handle->parent;
589         handle->child = NULL;
590         return cpp_read_line(handlep, n, buf);
591     }
592     else
593     {
594         if (n > handle->line_len)
595         {
596             handle->line_len = n;
597             srenew(handle->line, n);
598         }
599         strcpy(handle->line, buf);
600         handle->line_nr++;
601     }
602     /* Now we've read a line! */
603     if (debug)
604     {
605         fprintf(debug, "%s : %4d : %s\n", handle->fn, handle->line_nr, buf);
606     }
607
608     /* Process directives if this line contains one */
609     if (find_directive(buf, &dname, &dval))
610     {
611         status = process_directive(handlep, dname, dval);
612         if (status != eCPP_OK)
613         {
614             return status;
615         }
616         /* Don't print lines with directives, go on to the next */
617         return cpp_read_line(handlep, n, buf);
618     }
619
620     /* Check whether we're not ifdeffed out. The order of this statement
621        is important. It has to come after #ifdef, #else and #endif, but
622        anything else should be ignored. */
623     if (is_ifdeffed_out(handle))
624     {
625         return cpp_read_line(handlep, n, buf);
626     }
627
628     /* Check whether we have any defines that need to be replaced. Note
629        that we have to use a best fit algorithm, rather than first come
630        first go. We do this by sorting the defines on length first, and
631        then on alphabetical order. */
632     for (i = 0; (i < ndef); i++)
633     {
634         if (defs[i].def)
635         {
636             nn  = 0;
637             ptr = buf;
638             while ((ptr = strstrw(ptr, defs[i].name)) != NULL)
639             {
640                 nn++;
641                 ptr += strlen(defs[i].name);
642             }
643             if (nn > 0)
644             {
645                 len = strlen(buf) + nn*max(4, 4+strlen(defs[i].def)-strlen(defs[i].name));
646                 snew(name, len);
647                 ptr = buf;
648                 while ((ptr2 = strstrw(ptr, defs[i].name)) != NULL)
649                 {
650                     strncat(name, ptr, (int)(ptr2-ptr));
651                     strcat(name, defs[i].def);
652                     ptr = ptr2 + strlen(defs[i].name);
653                 }
654                 strcat(name, ptr);
655                 strcpy(buf, name);
656                 sfree(name);
657             }
658         }
659     }
660
661     return eCPP_OK;
662 }
663
664 char *cpp_cur_file(const gmx_cpp_t *handlep)
665 {
666     return (*handlep)->fn;
667 }
668
669 int cpp_cur_linenr(const gmx_cpp_t *handlep)
670 {
671     return (*handlep)->line_nr;
672 }
673
674 /* Close the file! Return integer status. */
675 int cpp_close_file(gmx_cpp_t *handlep)
676 {
677     int       i;
678     gmx_cpp_t handle = (gmx_cpp_t)*handlep;
679
680     if (!handle)
681     {
682         return eCPP_INVALID_HANDLE;
683     }
684     if (!handle->fp)
685     {
686         return eCPP_FILE_NOT_OPEN;
687     }
688     if (debug)
689     {
690         fprintf(debug, "GMXCPP: closing file %s\n", handle->fn);
691     }
692     fclose(handle->fp);
693     if (NULL != handle->cwd)
694     {
695         if (NULL != debug)
696         {
697             fprintf(debug, "GMXCPP: chdir to %s\n", handle->cwd);
698         }
699         gmx_chdir(handle->cwd);
700     }
701
702     if (0)
703     {
704         switch (errno)
705         {
706             case 0:
707                 break;
708             case ENOENT:
709                 return eCPP_FILE_NOT_FOUND;
710             case EBADF:
711                 return eCPP_FILE_NOT_OPEN;
712             case EINTR:
713                 return eCPP_INTERRUPT;
714             default:
715                 if (debug)
716                 {
717                     fprintf(debug, "Strange stuff closing file, errno = %d", errno);
718                 }
719                 return eCPP_UNKNOWN;
720         }
721     }
722     handle->fp      = NULL;
723     handle->line_nr = 0;
724     if (NULL != handle->fn)
725     {
726         sfree(handle->fn);
727         handle->fn = NULL;
728     }
729     if (NULL != handle->line)
730     {
731         sfree(handle->line);
732         handle->line = NULL;
733     }
734     if (NULL != handle->ifdefs)
735     {
736         sfree(handle->ifdefs);
737     }
738     handle->nifdef = 0;
739     if (NULL != handle->path)
740     {
741         sfree(handle->path);
742     }
743     if (NULL != handle->cwd)
744     {
745         sfree(handle->cwd);
746     }
747
748     return eCPP_OK;
749 }
750
751 /* Return a string containing the error message coresponding to status
752    variable */
753 char *cpp_error(gmx_cpp_t *handlep, int status)
754 {
755     char        buf[256];
756     const char *ecpp[] = {
757         "OK", "File not found", "End of file", "Syntax error", "Interrupted",
758         "Invalid file handle",
759         "File not open", "Unknown error", "Error status out of range"
760     };
761     gmx_cpp_t   handle = (gmx_cpp_t)*handlep;
762
763     if (!handle)
764     {
765         return (char *)ecpp[eCPP_INVALID_HANDLE];
766     }
767
768     if ((status < 0) || (status >= eCPP_NR))
769     {
770         status = eCPP_NR;
771     }
772
773     sprintf(buf, "%s - File %s, line %d\nLast line read:\n'%s'",
774             ecpp[status],
775             (handle && handle->fn) ? handle->fn : "unknown",
776             (handle) ? handle->line_nr : -1,
777             handle->line ? handle->line : "");
778
779     return strdup(buf);
780 }