]> SALOME platform Git repositories - modules/paravis.git/blob - src/VTKWrapping/ParaView/vtkParsePreprocess.c
Salome HOME
Synchronize adm files
[modules/paravis.git] / src / VTKWrapping / ParaView / vtkParsePreprocess.c
1 /*=========================================================================
2
3   Program:   Visualization Toolkit
4   Module:    vtkParsePreprocess.c
5
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16   Copyright (c) 2010 David Gobbi.
17
18   Contributed to the VisualizationToolkit by the author in June 2010
19   under the terms of the Visualization Toolkit 2008 copyright.
20 -------------------------------------------------------------------------*/
21
22 #include "vtkParsePreprocess.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <sys/stat.h>
28
29 /**
30   This file handles preprocessor directives via a simple
31   recursive-descent parser that only evaluates integers.
32 */
33
34 #define PREPROC_DEBUG 0
35
36 /** Block size for reading files */
37 #define FILE_BUFFER_SIZE 8192
38
39 /** Size of hash table must be a power of two */
40 #define PREPROC_HASH_TABLE_SIZE 1024u
41
42 /** Hashes for preprocessor keywords */
43 #define HASH_IFDEF      0x0fa4b283u
44 #define HASH_IFNDEF     0x04407ab1u
45 #define HASH_IF         0x00597834u
46 #define HASH_ELIF       0x7c964b25u
47 #define HASH_ELSE       0x7c964c6eu
48 #define HASH_ENDIF      0x0f60b40bu
49 #define HASH_DEFINED    0x088998d4u
50 #define HASH_DEFINE     0xf8804a70u
51 #define HASH_UNDEF      0x10823b97u
52 #define HASH_INCLUDE    0x9e36af89u
53 #define HASH_ERROR      0x0f6321efu
54 #define HASH_LINE       0x7c9a15adu
55 #define HASH_PRAGMA     0x1566a9fdu
56
57 /** Extend dynamic arrays in a progression of powers of two.
58  * Whenever "n" reaches a power of two, then the array size is
59  * doubled so that "n" can be safely incremented. */
60 static void *preproc_array_check(
61   void *arraymem, size_t size, int n)
62 {
63   /* if empty, alloc for the first time */
64   if (n == 0)
65     {
66     return malloc(size);
67     }
68   /* if count is power of two, reallocate with double size */
69   else if ((n & (n-1)) == 0)
70     {
71     return realloc(arraymem, (n << 1)*size);
72     }
73
74   /* no reallocation, just return the original array */
75   return arraymem;
76 }
77
78 /** Convert string to int. */
79 static preproc_int_t string_to_preproc_int(const char *cp, int base)
80 {
81 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
82   return _strtoi64(cp, NULL, base);
83 #else
84   return strtoll(cp, NULL, base);
85 #endif
86 }
87
88 /** Convert string to unsigned int. */
89 static preproc_uint_t string_to_preproc_uint(const char *cp, int base)
90 {
91 #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
92   return _strtoui64(cp, NULL, base);
93 #else
94   return strtoull(cp, NULL, base);
95 #endif
96 }
97
98 /** Tokenize and compare two strings */
99 static int preproc_identical(const char *text1, const char *text2)
100 {
101   int result = 1;
102
103   if (text1 != text2)
104     {
105     result = 0;
106
107     if (text1 && text2)
108       {
109       StringTokenizer t1;
110       StringTokenizer t2;
111
112       vtkParse_InitTokenizer(&t1, text1, WS_PREPROC);
113       vtkParse_InitTokenizer(&t2, text2, WS_PREPROC);
114
115       do
116         {
117         if (t1.tok != t2.tok ||
118             t1.hash != t2.hash ||
119             t1.len != t2.len ||
120             strncmp(t1.text, t2.text, t1.len) != 0)
121           {
122           break;
123           }
124         vtkParse_NextToken(&t1);
125         vtkParse_NextToken(&t2);
126         }
127       while (t1.tok && t2.tok);
128
129       result = (t1.tok == 0 && t2.tok == 0);
130       }
131     }
132
133   return result;
134 }
135
136 /** Create a new preprocessor macro. */
137 static MacroInfo *preproc_new_macro(
138   PreprocessInfo *info, const char *name, const char *definition)
139 {
140   MacroInfo *macro = (MacroInfo *)malloc(sizeof(MacroInfo));
141   vtkParsePreprocess_InitMacro(macro);
142
143   if (name)
144     {
145     size_t n = vtkParse_SkipId(name);
146     macro->Name = vtkParse_CacheString(info->Strings, name, n);
147     }
148
149   if (definition)
150     {
151     size_t n;
152     const char *cp = definition;
153     StringTokenizer tokens;
154     vtkParse_InitTokenizer(&tokens, cp, WS_PREPROC);
155
156     do
157       {
158       cp = tokens.text + tokens.len;
159       }
160     while (vtkParse_NextToken(&tokens));
161
162     n = cp - definition;
163     macro->Definition = vtkParse_CacheString(info->Strings, definition, n);
164     }
165
166   macro->IsExternal = info->IsExternal;
167
168   return macro;
169 }
170
171 /** Free a preprocessor macro struct. */
172 static void preproc_free_macro(MacroInfo *info)
173 {
174   free(info);
175 }
176
177 /** Find a preprocessor macro, return 0 if not found. */
178 static MacroInfo *preproc_find_macro(
179   PreprocessInfo *info, StringTokenizer *token)
180 {
181   unsigned int m = PREPROC_HASH_TABLE_SIZE - 1;
182   unsigned int i = (token->hash & m);
183   const char *name = token->text;
184   size_t l = token->len;
185   MacroInfo ***htable = info->MacroHashTable;
186   MacroInfo **hptr;
187   const char *mname;
188
189   if (htable && ((hptr = htable[i]) != NULL) && *hptr)
190     {
191     do
192       {
193       mname = (*hptr)->Name;
194       if (mname[0] == name[0] &&
195           strncmp(mname, name, l) == 0 &&
196           mname[l] == '\0')
197         {
198         return *hptr;
199         }
200       hptr++;
201       }
202     while (*hptr);
203     }
204
205   return NULL;
206 }
207
208 /** Return the address of the macro within the hash table.
209   * If "insert" is nonzero, add a new location if macro not found. */
210 static MacroInfo **preproc_macro_location(
211   PreprocessInfo *info, StringTokenizer *token, int insert)
212 {
213   MacroInfo ***htable = info->MacroHashTable;
214   unsigned int m = PREPROC_HASH_TABLE_SIZE - 1;
215   unsigned int i = (token->hash & m);
216   const char *name = token->text;
217   size_t l = token->len;
218   size_t n;
219   MacroInfo **hptr;
220   const char *mname;
221
222   if (htable == NULL)
223     {
224     if (!insert)
225       {
226       return NULL;
227       }
228
229     m = PREPROC_HASH_TABLE_SIZE;
230     htable = (MacroInfo ***)malloc(m*sizeof(MacroInfo **));
231     info->MacroHashTable = htable;
232     do { *htable++ = NULL; } while (--m);
233     htable = info->MacroHashTable;
234     }
235
236   hptr = htable[i];
237
238   if (hptr == NULL)
239     {
240     if (!insert)
241       {
242       return NULL;
243       }
244
245     hptr = (MacroInfo **)malloc(2*sizeof(MacroInfo *));
246     hptr[0] = NULL;
247     hptr[1] = NULL;
248     htable[i] = hptr;
249     }
250   else if (*hptr)
251     {
252     /* see if macro is already there */
253     n = 0;
254     do
255       {
256       mname = (*hptr)->Name;
257       if (mname[0] == name[0] &&
258           strncmp(mname, name, l) == 0 &&
259           mname[l] == '\0')
260         {
261         break;
262         }
263       n++;
264       hptr++;
265       }
266     while (*hptr);
267
268     if (*hptr == NULL)
269       {
270       if (!insert)
271         {
272         return NULL;
273         }
274
275       /* if n+1 is a power of two, double allocated space */
276       if (n > 0 && (n & (n+1)) == 0)
277         {
278         hptr = htable[i];
279         hptr = (MacroInfo **)realloc(hptr, (2*(n+1))*sizeof(MacroInfo *));
280         htable[i] = hptr;
281         hptr += n;
282         }
283
284       /* add a terminating null */
285       hptr[1] = NULL;
286       }
287     }
288
289   return hptr;
290 }
291
292 /** Remove a preprocessor macro.  Returns 0 if macro not found. */
293 static int preproc_remove_macro(
294   PreprocessInfo *info, StringTokenizer *token)
295 {
296   MacroInfo **hptr;
297
298   hptr = preproc_macro_location(info, token, 0);
299
300   if (hptr && *hptr)
301     {
302     preproc_free_macro(*hptr);
303
304     do
305       {
306       hptr[0] = hptr[1];
307       hptr++;
308       }
309     while (*hptr);
310
311     return 1;
312     }
313
314   return 0;
315 }
316
317 /** A simple way to add a preprocessor macro definition. */
318 static MacroInfo *preproc_add_macro_definition(
319   PreprocessInfo *info, const char *name, const char *definition)
320 {
321   StringTokenizer token;
322   MacroInfo *macro;
323   MacroInfo **macro_p;
324
325   vtkParse_InitTokenizer(&token, name, WS_PREPROC);
326
327   macro = preproc_new_macro(info, name, definition);
328   macro_p = preproc_macro_location(info, &token, 1);
329 #if PREPROC_DEBUG
330   if (*macro_p)
331     {
332     fprintf(stderr, "duplicate macro definition %s\n", name);
333     }
334 #endif
335   *macro_p = macro;
336
337   return macro;
338 }
339
340 /** Skip over parentheses, return nonzero if not closed. */
341 static int preproc_skip_parentheses(StringTokenizer *tokens)
342 {
343   int depth = 0;
344
345   if (tokens->tok == '(')
346     {
347     depth = 1;
348
349     while (depth > 0 && vtkParse_NextToken(tokens))
350       {
351       if (tokens->tok == '(')
352         {
353         depth++;
354         }
355       else if (tokens->tok == ')')
356         {
357         depth--;
358         }
359       }
360     }
361
362   if (tokens->tok == ')')
363     {
364     vtkParse_NextToken(tokens);
365     return VTK_PARSE_OK;
366     }
367
368 #if PREPROC_DEBUG
369   fprintf(stderr, "syntax error %d\n", __LINE__);
370 #endif
371   return VTK_PARSE_SYNTAX_ERROR;
372 }
373
374
375 /** Evaluate a char literal to an integer value. */
376 static int preproc_evaluate_char(
377   const char *cp, preproc_int_t *val, int *is_unsigned)
378 {
379   if (cp[0] == '\'')
380     {
381     cp++;
382     if (*cp != '\\')
383       {
384       *val = *cp;
385       }
386     else if (*cp != '\'' && *cp != '\n' && *cp != '\0')
387       {
388       cp++;
389       if (*cp == 'a') { *val = '\a'; }
390       else if (*cp == 'b') { *val = '\b'; }
391       else if (*cp == 'f') { *val = '\f'; }
392       else if (*cp == 'n') { *val = '\n'; }
393       else if (*cp == 'r') { *val = '\r'; }
394       else if (*cp == 'b') { *val = '\b'; }
395       else if (*cp == 't') { *val = '\t'; }
396       else if (*cp == 'v') { *val = '\v'; }
397       else if (*cp == '\'') { *val = '\''; }
398       else if (*cp == '\"') { *val = '\"'; }
399       else if (*cp == '\\') { *val = '\\'; }
400       else if (*cp == '\?') { *val = '\?'; }
401       else if (*cp == '0')
402         {
403         *val = string_to_preproc_int(cp, 8);
404         do { cp++; } while (*cp >= '0' && *cp <= '7');
405         }
406       else if (*cp == 'x')
407         {
408         *val = string_to_preproc_int(cp+1, 16);
409         do { cp++; } while (vtkParse_CharType(*cp, CPRE_HEX));
410         }
411       }
412     if (*cp != '\'')
413       {
414 #if PREPROC_DEBUG
415       fprintf(stderr, "syntax error %d\n", __LINE__);
416 #endif
417       return VTK_PARSE_SYNTAX_ERROR;
418       }
419     cp++;
420     *is_unsigned = 0;
421     return VTK_PARSE_OK;
422     }
423
424 #if PREPROC_DEBUG
425   fprintf(stderr, "syntax error %d\n", __LINE__);
426 #endif
427   return VTK_PARSE_SYNTAX_ERROR;
428 }
429
430 /* Evaluate an integer, ignoring any suffixes except 'u'. */
431 static int preproc_evaluate_integer(
432   const char *cp, preproc_int_t *val, int *is_unsigned)
433 {
434   const char *ep;
435   int base = 0;
436   ep = cp;
437
438   if (cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X'))
439     {
440     cp += 2;
441     base = 16;
442     *is_unsigned = 1;
443     ep = cp;
444     while (vtkParse_CharType(*ep, CPRE_HEX))
445       {
446       ep++;
447       }
448     }
449   else if (cp[0] == '0' && vtkParse_CharType(cp[1], CPRE_DIGIT))
450     {
451     cp += 1;
452     base = 8;
453     *is_unsigned = 1;
454     ep = cp;
455     while (*ep >= '0' && *ep <= '7')
456       {
457       ep++;
458       }
459     }
460   else
461     {
462     base = 10;
463     *is_unsigned = 0;
464     while (vtkParse_CharType(*ep, CPRE_DIGIT))
465       {
466       ep++;
467       }
468     }
469
470   for (;;)
471     {
472     if (ep[0] == 'i' && ep[1] == '6' && ep[2] == '4') { ep += 3; }
473     else if (*ep == 'u') { *is_unsigned = 1; ep++; }
474     else if (*ep == 'l' || *ep == 'L') { ep++; }
475     else { break; }
476     }
477
478   if (*is_unsigned)
479     {
480     *val = (preproc_int_t)string_to_preproc_uint(cp, base);
481     }
482   else
483     {
484     *val = string_to_preproc_int(cp, base);
485     }
486
487   if (*ep == '.' || *ep == 'e' || *ep == 'E')
488     {
489     return VTK_PARSE_PREPROC_DOUBLE;
490     }
491
492   return VTK_PARSE_OK;
493 }
494
495 /* forward declaration */
496 static int preproc_evaluate_expression(
497   PreprocessInfo *info, StringTokenizer *tokens,
498   preproc_int_t *val, int *is_unsigned);
499
500 /** Evaluate a single item in an expression. */
501 static int preproc_evaluate_single(
502   PreprocessInfo *info, StringTokenizer *tokens,
503   preproc_int_t *val, int *is_unsigned)
504 {
505   int result = VTK_PARSE_OK;
506
507   while (tokens->tok == TOK_ID)
508     {
509     /* handle the "defined" keyword */
510     if (tokens->hash == HASH_DEFINED && tokens->len == 7 &&
511         strncmp("defined", tokens->text, tokens->len) == 0)
512       {
513       int paren = 0;
514       vtkParse_NextToken(tokens);
515
516       if (tokens->tok == '(')
517         {
518         paren = 1;
519         vtkParse_NextToken(tokens);
520         }
521       if (tokens->tok != TOK_ID)
522         {
523         *val = 0;
524         *is_unsigned = 0;
525 #if PREPROC_DEBUG
526         fprintf(stderr, "syntax error %d\n", __LINE__);
527 #endif
528         return VTK_PARSE_SYNTAX_ERROR;
529         }
530
531       /* do the name lookup */
532       *is_unsigned = 0;
533       *val = (preproc_find_macro(info, tokens) != 0);
534
535       vtkParse_NextToken(tokens);
536       if (paren)
537         {
538         if (tokens->tok != ')')
539           {
540 #if PREPROC_DEBUG
541           fprintf(stderr, "syntax error %d\n", __LINE__);
542 #endif
543           return VTK_PARSE_SYNTAX_ERROR;
544           }
545         vtkParse_NextToken(tokens);
546         }
547
548       return result;
549       }
550     else
551       {
552       /* look up and evaluate the macro */
553       MacroInfo *macro = preproc_find_macro(info, tokens);
554       const char *args = NULL;
555       const char *expansion = NULL;
556       const char *cp;
557       vtkParse_NextToken(tokens);
558       *val = 0;
559       *is_unsigned = 0;
560
561       if (macro == NULL || macro->IsExcluded)
562         {
563         return VTK_PARSE_MACRO_UNDEFINED;
564         }
565       else if (macro->IsFunction)
566         {
567         /* expand function macros using the arguments */
568         args = tokens->text;
569         if (tokens->tok != '(' ||
570             preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
571           {
572 #if PREPROC_DEBUG
573           fprintf(stderr, "syntax error %d\n", __LINE__);
574 #endif
575           return VTK_PARSE_SYNTAX_ERROR;
576           }
577         }
578       expansion = vtkParsePreprocess_ExpandMacro(info, macro, args);
579       if (expansion == NULL)
580         {
581         free((char *)args);
582 #if PREPROC_DEBUG
583         fprintf(stderr, "syntax error %d\n", __LINE__);
584 #endif
585         return (args ? VTK_PARSE_MACRO_NUMARGS : VTK_PARSE_SYNTAX_ERROR);
586         }
587       cp = expansion;
588       cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
589       if (*cp != '\0')
590         {
591         macro->IsExcluded = 1;
592         result = vtkParsePreprocess_EvaluateExpression(
593           info, expansion, val, is_unsigned);
594         macro->IsExcluded = 0;
595         vtkParsePreprocess_FreeMacroExpansion(
596           info, macro, expansion);
597         return result;
598         }
599       vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
600       }
601     /* if macro expansion was empty, continue */
602     }
603
604   if (tokens->tok == '(')
605     {
606     vtkParse_NextToken(tokens);
607     result = preproc_evaluate_expression(info, tokens, val, is_unsigned);
608     if ((result & VTK_PARSE_FATAL_ERROR) == 0)
609       {
610       if (tokens->tok == ')')
611         {
612         vtkParse_NextToken(tokens);
613         return result;
614         }
615 #if PREPROC_DEBUG
616       fprintf(stderr, "syntax error %d\n", __LINE__);
617 #endif
618       return VTK_PARSE_SYNTAX_ERROR;
619       }
620     return result;
621     }
622   else if (tokens->tok == TOK_NUMBER)
623     {
624     result = preproc_evaluate_integer(tokens->text, val, is_unsigned);
625     if (tokens->text[tokens->len-1] == 'f' ||
626         tokens->text[tokens->len-1] == 'F')
627       {
628       result = VTK_PARSE_PREPROC_FLOAT;
629       }
630     vtkParse_NextToken(tokens);
631     return result;
632     }
633   else if (tokens->tok == TOK_CHAR)
634     {
635     result = preproc_evaluate_char(tokens->text, val, is_unsigned);
636     vtkParse_NextToken(tokens);
637     return result;
638     }
639   else if (tokens->tok == TOK_STRING)
640     {
641     *val = 0;
642     *is_unsigned = 0;
643     vtkParse_NextToken(tokens);
644     while (tokens->tok == TOK_STRING)
645       {
646       vtkParse_NextToken(tokens);
647       }
648     return VTK_PARSE_PREPROC_STRING;
649     }
650
651   *val = 0;
652   *is_unsigned = 0;
653 #if PREPROC_DEBUG
654   fprintf(stderr, "syntax error %d \"%*.*s\"\n", __LINE__,
655           (int)tokens->len, (int)tokens->len, tokens->text);
656 #endif
657   return VTK_PARSE_SYNTAX_ERROR;
658 }
659
660 static int preproc_evaluate_unary(
661   PreprocessInfo *info, StringTokenizer *tokens,
662   preproc_int_t *val, int *is_unsigned)
663 {
664   int op = tokens->tok;
665   int result = VTK_PARSE_OK;
666
667   if (op != '+' && op != '-' && op != '~' && op != '!')
668     {
669     return preproc_evaluate_single(info, tokens, val, is_unsigned);
670     }
671
672   vtkParse_NextToken(tokens);
673
674   result = preproc_evaluate_unary(info, tokens, val, is_unsigned);
675   if ((result & VTK_PARSE_FATAL_ERROR) == 0)
676     {
677     if (op == '~') { *val = ~(*val); }
678     else if (op == '!') { *val = !(*val); *is_unsigned = 0; }
679     else if (op == '-') { *val = -(*val); }
680     return result;
681     }
682
683   return result;
684 }
685
686 static int preproc_evaluate_multiply(
687   PreprocessInfo *info, StringTokenizer *tokens,
688   preproc_int_t *val, int *is_unsigned)
689 {
690   int op;
691   preproc_int_t rval;
692   int rtype;
693   int result;
694
695   result = preproc_evaluate_unary(info, tokens, val, is_unsigned);
696   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
697     {
698     op = tokens->tok;
699     if (op != '*' && op != '/' && op != '%')
700       {
701       return result;
702       }
703
704     vtkParse_NextToken(tokens);
705
706     result = preproc_evaluate_unary(info, tokens, &rval, &rtype);
707
708     *is_unsigned = (*is_unsigned || rtype);
709
710     if (*is_unsigned)
711       {
712       if (op == '*')
713         {
714         *val = (preproc_int_t)((preproc_uint_t)*val *
715                                 (preproc_uint_t)rval);
716         }
717       else if (op == '/')
718         {
719         if (rval != 0)
720           {
721           *val = (preproc_int_t)((preproc_uint_t)*val /
722                                  (preproc_uint_t)rval);
723           }
724         else
725           {
726           *val = 2147483647;
727           }
728         }
729       else if (op == '%')
730         {
731         if (rval != 0)
732           {
733           *val = (preproc_int_t)((preproc_uint_t)*val %
734                                   (preproc_uint_t)rval);
735           }
736         else
737           {
738           *val = 2147483647;
739           }
740         }
741       }
742     else
743       {
744       if (op == '*')
745         {
746         *val = *val * rval;
747         }
748       else if (op == '/')
749         {
750         if (rval != 0)
751           {
752           *val = *val / rval;
753           }
754         else if (*val < 0)
755           {
756           *val = -2147483647;
757           }
758         else
759           {
760           *val = 2147483647;
761           }
762         }
763       else if (op == '%')
764         {
765         if (rval != 0)
766           {
767           *val = *val % rval;
768           }
769         else if (*val < 0)
770           {
771           *val = -2147483647;
772           }
773         else
774           {
775           *val = 2147483647;
776           }
777         }
778       }
779     }
780
781   return result;
782 }
783
784 static int preproc_evaluate_add(
785   PreprocessInfo *info, StringTokenizer *tokens,
786   preproc_int_t *val, int *is_unsigned)
787 {
788   int op;
789   preproc_int_t rval;
790   int rtype;
791   int result;
792
793   result = preproc_evaluate_multiply(info, tokens, val, is_unsigned);
794   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
795     {
796     op = tokens->tok;
797     if (op != '+' && op != '-')
798       {
799       return result;
800       }
801
802     vtkParse_NextToken(tokens);
803
804     result = preproc_evaluate_multiply(info, tokens, &rval, &rtype);
805
806     *is_unsigned = (*is_unsigned || rtype);
807
808     if (op == '+')
809       {
810       *val = *val + rval;
811       }
812     else if (op == '-')
813       {
814       *val = *val - rval;
815       }
816     }
817
818   return result;
819 }
820
821 static int preproc_evaluate_bitshift(
822   PreprocessInfo *info, StringTokenizer *tokens,
823   preproc_int_t *val, int *is_unsigned)
824 {
825   int op;
826   preproc_int_t rval;
827   int rtype;
828   int result;
829
830   result = preproc_evaluate_add(info, tokens, val, is_unsigned);
831   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
832     {
833     op = tokens->tok;
834
835     if (op != TOK_LSHIFT && op != TOK_RSHIFT)
836       {
837       return result;
838       }
839
840     vtkParse_NextToken(tokens);
841
842     result = preproc_evaluate_add(info, tokens, &rval, &rtype);
843
844     if (*is_unsigned)
845       {
846       if (op == TOK_LSHIFT)
847         {
848         *val = (preproc_int_t)((preproc_uint_t)*val << rval);
849         }
850       else if (op == TOK_RSHIFT)
851         {
852         *val = (preproc_int_t)((preproc_uint_t)*val >> rval);
853         }
854       }
855     else
856       {
857       if (op == TOK_LSHIFT)
858         {
859         *val = *val << rval;
860         }
861       else if (op == TOK_RSHIFT)
862         {
863         *val = *val >> rval;
864         }
865       }
866     }
867
868   return result;
869 }
870
871 static int preproc_evaluate_compare(
872   PreprocessInfo *info, StringTokenizer *tokens,
873   preproc_int_t *val, int *is_unsigned)
874 {
875   int op;
876   preproc_int_t rval;
877   int rtype;
878   int result;
879
880   result = preproc_evaluate_bitshift(info, tokens, val, is_unsigned);
881   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
882     {
883     op = tokens->tok;
884     if (op != '<' && op != '>' && op != TOK_LE && op != TOK_GE)
885       {
886       return result;
887       }
888
889     vtkParse_NextToken(tokens);
890
891     result = preproc_evaluate_bitshift(info, tokens, &rval, &rtype);
892
893     *is_unsigned = (*is_unsigned || rtype);
894
895     if (*is_unsigned)
896       {
897       if (op == TOK_LE)
898         {
899         *val = ((preproc_uint_t)*val <= (preproc_uint_t)rval);
900         }
901       else if (op == '<')
902         {
903         *val = ((preproc_uint_t)*val < (preproc_uint_t)rval);
904         }
905       else if (op == TOK_GE)
906         {
907         *val = ((preproc_uint_t)*val >= (preproc_uint_t)rval);
908         }
909       else if (op == '>')
910         {
911         *val = ((preproc_uint_t)*val > (preproc_uint_t)rval);
912         }
913       }
914     else
915       {
916       if (op == TOK_LE)
917         {
918         *val = (*val <= rval);
919         }
920       else if (op == '<')
921         {
922         *val = (*val < rval);
923         }
924       else if (op == TOK_GE)
925         {
926         *val = (*val >= rval);
927         }
928       else if (op == '>')
929         {
930         *val = (*val > rval);
931         }
932       }
933     *is_unsigned = 0;
934     }
935
936   return result;
937 }
938
939 static int preproc_evaluate_equal(
940   PreprocessInfo *info, StringTokenizer *tokens,
941   preproc_int_t *val, int *is_unsigned)
942 {
943   int op;
944   preproc_int_t rval;
945   int rtype;
946   int result;
947
948   result = preproc_evaluate_compare(info, tokens, val, is_unsigned);
949   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
950     {
951     op = tokens->tok;
952     if (op != TOK_EQ && op != TOK_NE)
953       {
954       return result;
955       }
956
957     vtkParse_NextToken(tokens);
958
959     result = preproc_evaluate_compare(info, tokens, &rval, &rtype);
960
961     if (op == TOK_EQ)
962       {
963       *val = (*val == rval);
964       }
965     else if (op == TOK_NE)
966       {
967       *val = (*val != rval);
968       }
969     *is_unsigned = 0;
970     }
971
972   return result;
973 }
974
975 static int preproc_evaluate_and(
976   PreprocessInfo *info, StringTokenizer *tokens,
977   preproc_int_t *val, int *is_unsigned)
978 {
979   preproc_int_t rval;
980   int rtype;
981   int result;
982
983   result = preproc_evaluate_equal(info, tokens, val, is_unsigned);
984   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
985     {
986     if (tokens->tok != '&')
987       {
988       return result;
989       }
990
991     vtkParse_NextToken(tokens);
992
993     result = preproc_evaluate_equal(info, tokens, &rval, &rtype);
994
995     *is_unsigned = (*is_unsigned || rtype);
996     *val = (*val & rval);
997     }
998
999   return result;
1000 }
1001
1002 static int preproc_evaluate_xor(
1003   PreprocessInfo *info, StringTokenizer *tokens,
1004   preproc_int_t *val, int *is_unsigned)
1005 {
1006   preproc_int_t rval;
1007   int rtype;
1008   int result;
1009
1010   result = preproc_evaluate_and(info, tokens, val, is_unsigned);
1011   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1012     {
1013     if (tokens->tok != '^')
1014       {
1015       return result;
1016       }
1017
1018     vtkParse_NextToken(tokens);
1019
1020     result = preproc_evaluate_and(info, tokens, &rval, &rtype);
1021
1022     *is_unsigned = (*is_unsigned || rtype);
1023     *val = (*val ^ rval);
1024     }
1025
1026   return result;
1027 }
1028
1029 static int preproc_evaluate_or(
1030   PreprocessInfo *info, StringTokenizer *tokens,
1031   preproc_int_t *val, int *is_unsigned)
1032 {
1033   preproc_int_t rval;
1034   int rtype;
1035   int result;
1036
1037   result = preproc_evaluate_xor(info, tokens, val, is_unsigned);
1038   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1039     {
1040     if (tokens->tok != '|')
1041       {
1042       return result;
1043       }
1044
1045     vtkParse_NextToken(tokens);
1046
1047     result = preproc_evaluate_xor(info, tokens, &rval, &rtype);
1048
1049     *is_unsigned = (*is_unsigned || rtype);
1050     *val = (*val | rval);
1051     }
1052
1053   return result;
1054 }
1055
1056 static int preproc_evaluate_logic_and(
1057   PreprocessInfo *info, StringTokenizer *tokens,
1058   preproc_int_t *val, int *is_unsigned)
1059 {
1060   preproc_int_t rval;
1061   int rtype;
1062   int result;
1063
1064   result = preproc_evaluate_or(info, tokens, val, is_unsigned);
1065   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1066     {
1067     if (tokens->tok != TOK_AND)
1068       {
1069       return result;
1070       }
1071
1072     vtkParse_NextToken(tokens);
1073
1074     if (*val == 0)
1075       {
1076       /* short circuit */
1077       while (tokens->tok != 0 && tokens->tok != ')' &&
1078              tokens->tok != ':' && tokens->tok != '?' &&
1079              tokens->tok != ',' && tokens->tok != TOK_OR)
1080         {
1081         if (tokens->tok == '(')
1082           {
1083           if (preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
1084             {
1085 #if PREPROC_DEBUG
1086             fprintf(stderr, "syntax error %d\n", __LINE__);
1087 #endif
1088             result = VTK_PARSE_SYNTAX_ERROR;
1089             }
1090           }
1091         else
1092           {
1093           vtkParse_NextToken(tokens);
1094           }
1095         }
1096
1097       *is_unsigned = 0;
1098
1099       return result;
1100       }
1101
1102     result = preproc_evaluate_or(info, tokens, &rval, &rtype);
1103
1104     *is_unsigned = 0;
1105     *val = (rval != 0);
1106     }
1107
1108   return result;
1109 }
1110
1111 static int preproc_evaluate_logic_or(
1112   PreprocessInfo *info, StringTokenizer *tokens,
1113   preproc_int_t *val, int *is_unsigned)
1114 {
1115   preproc_int_t rval;
1116   int rtype;
1117   int result;
1118
1119   result = preproc_evaluate_logic_and(info, tokens, val, is_unsigned);
1120   while ((result & VTK_PARSE_FATAL_ERROR) == 0)
1121     {
1122     if (tokens->tok != TOK_OR)
1123       {
1124       return result;
1125       }
1126
1127     vtkParse_NextToken(tokens);
1128
1129     if (*val != 0)
1130       {
1131       /* short circuit */
1132       while (tokens->tok != 0 && tokens->tok != ')' &&
1133              tokens->tok != ':' && tokens->tok != '?' &&
1134              tokens->tok != ',')
1135         {
1136         if (tokens->tok == '(')
1137           {
1138           if (preproc_skip_parentheses(tokens) != VTK_PARSE_OK)
1139             {
1140 #if PREPROC_DEBUG
1141             fprintf(stderr, "syntax error %d\n", __LINE__);
1142 #endif
1143             result = VTK_PARSE_SYNTAX_ERROR;
1144             }
1145           }
1146         else
1147           {
1148           vtkParse_NextToken(tokens);
1149           }
1150         }
1151
1152       *is_unsigned = 0;
1153
1154       return result;
1155       }
1156
1157     result = preproc_evaluate_logic_and(info, tokens, &rval, &rtype);
1158
1159     *is_unsigned = 0;
1160     *val = (rval != 0);
1161     }
1162
1163   return result;
1164 }
1165
1166 /** Evaluate an arimetic *expression.  */
1167 int preproc_evaluate_expression(
1168   PreprocessInfo *info, StringTokenizer *tokens,
1169   preproc_int_t *val, int *is_unsigned)
1170 {
1171   preproc_int_t rval, sval;
1172   int rtype, stype;
1173   int result;
1174
1175   result = preproc_evaluate_logic_or(info, tokens, val, is_unsigned);
1176   if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1177     {
1178     if (tokens->tok != '?')
1179       {
1180       return result;
1181       }
1182
1183     vtkParse_NextToken(tokens);
1184
1185     result = preproc_evaluate_expression(info, tokens, &rval, &rtype);
1186     if ((result & VTK_PARSE_FATAL_ERROR) != 0)
1187       {
1188       return result;
1189       }
1190
1191     if (tokens->tok != ':')
1192       {
1193 #if PREPROC_DEBUG
1194       fprintf(stderr, "syntax error %d\n", __LINE__);
1195 #endif
1196       return VTK_PARSE_SYNTAX_ERROR;
1197       }
1198
1199     vtkParse_NextToken(tokens);
1200
1201     result = preproc_evaluate_expression(info, tokens, &sval, &stype);
1202     if ((result & VTK_PARSE_FATAL_ERROR) != 0)
1203       {
1204       return result;
1205       }
1206
1207     if (*val != 0)
1208       {
1209       *val = rval;
1210       *is_unsigned = rtype;
1211       }
1212     else
1213       {
1214       *val = sval;
1215       *is_unsigned = stype;
1216       }
1217     }
1218
1219   return result;
1220 }
1221
1222 /** Evaluate a conditional *expression.
1223  * Returns VTK_PARSE_OK if the expression is true,
1224  * or VTK_PARSE_SKIP of the expression is false. */
1225 int preproc_evaluate_conditional(
1226   PreprocessInfo *info, StringTokenizer *tokens)
1227 {
1228   preproc_int_t rval;
1229   int rtype;
1230   int result;
1231
1232   result = preproc_evaluate_expression(info, tokens, &rval, &rtype);
1233   if ((result & VTK_PARSE_FATAL_ERROR) == 0)
1234     {
1235     if (tokens->tok != 0)
1236       {
1237 #if PREPROC_DEBUG
1238       fprintf(stderr, "syntax error %d\n", __LINE__);
1239 #endif
1240       return VTK_PARSE_SYNTAX_ERROR;
1241       }
1242     return (rval == 0 ? VTK_PARSE_SKIP : VTK_PARSE_OK);
1243     }
1244
1245   return result;
1246 }
1247
1248 /**
1249  * Handle any of the following directives:
1250  * #if, #ifdef, #ifndef, #elif, #else, #endif
1251  * A return value of VTK_PARSE_SKIP means that
1252  * the following code block should be skipped.
1253  */
1254 static int preproc_evaluate_if(
1255   PreprocessInfo *info, StringTokenizer *tokens)
1256 {
1257   MacroInfo *macro;
1258   int v1, v2;
1259   int result = VTK_PARSE_OK;
1260
1261   if (tokens->hash == HASH_IF ||
1262       tokens->hash == HASH_IFDEF ||
1263       tokens->hash == HASH_IFNDEF)
1264     {
1265     if (info->ConditionalDepth == 0)
1266       {
1267       if (tokens->hash == HASH_IF)
1268         {
1269         vtkParse_NextToken(tokens);
1270         result = preproc_evaluate_conditional(info, tokens);
1271         }
1272       else
1273         {
1274         v1 = (tokens->hash != HASH_IFNDEF);
1275         vtkParse_NextToken(tokens);
1276         if (tokens->tok != TOK_ID)
1277           {
1278 #if PREPROC_DEBUG
1279           fprintf(stderr, "syntax error %d\n", __LINE__);
1280 #endif
1281           return VTK_PARSE_SYNTAX_ERROR;
1282           }
1283         macro = preproc_find_macro(info, tokens);
1284         v2 = (macro && !macro->IsExcluded);
1285         vtkParse_NextToken(tokens);
1286         result = ( (v1 ^ v2) ? VTK_PARSE_SKIP : VTK_PARSE_OK);
1287         }
1288
1289       if (result != VTK_PARSE_SKIP)
1290         {
1291         /* mark as done, so that the "else" clause is skipped */
1292         info->ConditionalDone = 1;
1293         }
1294       else
1295         {
1296         /* mark as not done, so that "else" clause is not skipped */
1297         info->ConditionalDone = 0;
1298         /* skip the "if" clause */
1299         info->ConditionalDepth = 1;
1300         }
1301       }
1302     else
1303       {
1304       /* increase the skip depth */
1305       info->ConditionalDepth++;
1306       }
1307     }
1308   else if (tokens->hash == HASH_ELIF ||
1309            tokens->hash == HASH_ELSE)
1310     {
1311     if (info->ConditionalDepth == 0)
1312       {
1313       /* preceding clause was not skipped, so must skip this one */
1314       info->ConditionalDepth = 1;
1315       }
1316     else if (info->ConditionalDepth == 1 &&
1317              info->ConditionalDone == 0)
1318       {
1319       if (tokens->hash == HASH_ELIF)
1320         {
1321         vtkParse_NextToken(tokens);
1322         result = preproc_evaluate_conditional(info, tokens);
1323         }
1324       else
1325         {
1326         vtkParse_NextToken(tokens);
1327         }
1328       if (result != VTK_PARSE_SKIP)
1329         {
1330         /* do not skip this clause */
1331         info->ConditionalDepth = 0;
1332         /* make sure remaining else/elif clauses are skipped */
1333         info->ConditionalDone = 1;
1334         }
1335       }
1336     }
1337   else if (tokens->hash == HASH_ENDIF)
1338     {
1339     vtkParse_NextToken(tokens);
1340     if (info->ConditionalDepth > 0)
1341       {
1342       /* decrease the skip depth */
1343       info->ConditionalDepth--;
1344       }
1345     if (info->ConditionalDepth == 0)
1346       {
1347       /* set "done" flag for the context that is being returned to */
1348       info->ConditionalDone = 1;
1349       }
1350     }
1351
1352   return result;
1353 }
1354
1355 /**
1356  * Handle the #define and #undef directives.
1357  */
1358 static int preproc_evaluate_define(
1359   PreprocessInfo *info, StringTokenizer *tokens)
1360 {
1361   MacroInfo **macro_p;
1362   MacroInfo *macro;
1363   int is_function;
1364   int is_variadic;
1365   const char *name;
1366   size_t namelen;
1367   const char *definition = 0;
1368   int n = 0;
1369   const char **params = NULL;
1370   const char *param;
1371   size_t l;
1372
1373   if (tokens->hash == HASH_DEFINE)
1374     {
1375     vtkParse_NextToken(tokens);
1376     if (tokens->tok != TOK_ID)
1377       {
1378 #if PREPROC_DEBUG
1379       fprintf(stderr, "syntax error %d\n", __LINE__);
1380 #endif
1381       return VTK_PARSE_SYNTAX_ERROR;
1382       }
1383
1384     macro_p = preproc_macro_location(info, tokens, 1);
1385     name = tokens->text;
1386     namelen = tokens->len;
1387     vtkParse_NextToken(tokens);
1388
1389     is_function = 0;
1390     is_variadic = 0;
1391     if (name[namelen] == '(')
1392       {
1393       is_function = 1;
1394       vtkParse_NextToken(tokens);
1395       while (tokens->tok != 0 && tokens->tok != ')')
1396         {
1397         if (tokens->tok != TOK_ID && tokens->tok != TOK_ELLIPSIS)
1398           {
1399           if (params) { free((char **)params); }
1400 #if PREPROC_DEBUG
1401           fprintf(stderr, "syntax error %d\n", __LINE__);
1402 #endif
1403           return VTK_PARSE_SYNTAX_ERROR;
1404           }
1405
1406         param = tokens->text;
1407         l = tokens->len;
1408
1409         if (tokens->tok == TOK_ELLIPSIS)
1410           {
1411           is_variadic = 1;
1412           param = "__VA_ARGS__";
1413           l = 11;
1414           }
1415
1416         /* add to the arg list */
1417         params = (const char **)preproc_array_check(
1418           (char **)params, sizeof(char *), n);
1419         params[n++] = vtkParse_CacheString(info->Strings, param, l);
1420
1421         vtkParse_NextToken(tokens);
1422
1423         /* check for gnu cpp "arg..." parameter */
1424         if (tokens->tok == TOK_ELLIPSIS)
1425           {
1426           is_variadic = 1;
1427           vtkParse_NextToken(tokens);
1428           }
1429
1430         if (tokens->tok == ',')
1431           {
1432           vtkParse_NextToken(tokens);
1433           }
1434         else if (tokens->tok != ')')
1435           {
1436           if (params) { free((char **)params); }
1437 #if PREPROC_DEBUG
1438           fprintf(stderr, "syntax error %d\n", __LINE__);
1439 #endif
1440           return VTK_PARSE_SYNTAX_ERROR;
1441           }
1442         }
1443       vtkParse_NextToken(tokens);
1444       }
1445
1446     if (tokens->tok)
1447       {
1448       definition = tokens->text;
1449       }
1450
1451     macro = *macro_p;
1452     if (macro)
1453       {
1454       if (preproc_identical(macro->Definition, definition))
1455         {
1456         return VTK_PARSE_OK;
1457         }
1458       if (params) { free((char **)params); }
1459 #if PREPROC_DEBUG
1460       fprintf(stderr, "macro redefined %d\n", __LINE__);
1461 #endif
1462       return VTK_PARSE_MACRO_REDEFINED;
1463       }
1464
1465     macro = preproc_new_macro(info, name, definition);
1466     macro->IsFunction = is_function;
1467     macro->IsVariadic = is_variadic;
1468     macro->NumberOfParameters = n;
1469     macro->Parameters = params;
1470     *macro_p = macro;
1471
1472     return VTK_PARSE_OK;
1473     }
1474   else if (tokens->hash == HASH_UNDEF)
1475     {
1476     vtkParse_NextToken(tokens);
1477     if (tokens->tok != TOK_ID)
1478       {
1479 #if PREPROC_DEBUG
1480       fprintf(stderr, "syntax error %d\n", __LINE__);
1481 #endif
1482       return VTK_PARSE_SYNTAX_ERROR;
1483       }
1484     preproc_remove_macro(info, tokens);
1485     return VTK_PARSE_OK;
1486     }
1487
1488   return VTK_PARSE_OK;
1489 }
1490
1491 /**
1492  * Add an include file to the list.  Return 0 if it is already there.
1493  */
1494 static int preproc_add_include_file(PreprocessInfo *info, const char *name)
1495 {
1496   int i, n;
1497
1498   n = info->NumberOfIncludeFiles;
1499   for (i = 0; i < n; i++)
1500     {
1501     if (strcmp(info->IncludeFiles[i], name) == 0)
1502       {
1503       return 0;
1504       }
1505     }
1506
1507   info->IncludeFiles = (const char **)preproc_array_check(
1508     (char **)info->IncludeFiles, sizeof(char *), info->NumberOfIncludeFiles);
1509   info->IncludeFiles[info->NumberOfIncludeFiles++] =
1510     vtkParse_CacheString(info->Strings, name, strlen(name));
1511
1512   return 1;
1513 }
1514
1515 /**
1516  * Find an include file.  If "cache_only" is set, then do a check to
1517  * see if the file was previously found without going to the filesystem.
1518  */
1519 const char *preproc_find_include_file(
1520   PreprocessInfo *info, const char *filename, int system_first,
1521   int cache_only)
1522 {
1523   int i, n, ii, nn;
1524   size_t j, m;
1525   struct stat fs;
1526   const char *directory;
1527   char *output;
1528   size_t outputsize = 16;
1529   int count;
1530
1531   /* allow filename to be terminated by quote or bracket */
1532   m = 0;
1533   while (filename[m] != '\"' && filename[m] != '>' &&
1534          filename[m] != '\n' && filename[m] != '\0') { m++; }
1535
1536   /* search file system for the file */
1537   output = (char *)malloc(outputsize);
1538
1539   if (system_first != 0)
1540     {
1541     system_first = 1;
1542     }
1543
1544   if (cache_only != 0)
1545     {
1546     cache_only = 1;
1547     }
1548
1549   /* check for absolute path of form DRIVE: or /path/to/file */
1550   j = 0;
1551   while (vtkParse_CharType(filename[j], CPRE_IDGIT)) { j++; }
1552
1553   if (filename[j] == ':' || filename[0] == '/' || filename[0] == '\\')
1554     {
1555     if (m+1 > outputsize)
1556       {
1557       outputsize += m+1;
1558       output = (char *)realloc(output, outputsize);
1559       }
1560     strncpy(output, filename, m);
1561     output[m] = '\0';
1562
1563     nn = info->NumberOfIncludeFiles;
1564     for (ii = 0; ii < nn; ii++)
1565       {
1566       if (strcmp(output, info->IncludeFiles[ii]) == 0)
1567         {
1568         free(output);
1569         return info->IncludeFiles[ii];
1570         }
1571       }
1572
1573     if (cache_only)
1574       {
1575       free(output);
1576       return NULL;
1577       }
1578
1579     info->IncludeFiles = (const char **)preproc_array_check(
1580       (char **)info->IncludeFiles, sizeof(char *),
1581       info->NumberOfIncludeFiles);
1582     info->IncludeFiles[info->NumberOfIncludeFiles++] = output;
1583
1584     return output;
1585     }
1586
1587   /* Make sure the current filename is already added */
1588   if (info->FileName)
1589     {
1590     preproc_add_include_file(info, info->FileName);
1591     }
1592
1593   /* Check twice. First check the cache, then stat the files. */
1594   for (count = 0; count < (2-cache_only); count++)
1595     {
1596     n = info->NumberOfIncludeDirectories;
1597     for (i = 0; i < (n+1-system_first); i++)
1598       {
1599       /* search the directory of the file being processed */
1600       if (i == 0 && system_first == 0)
1601         {
1602         if (info->FileName)
1603           {
1604           j = strlen(info->FileName);
1605           while (j > 0)
1606             {
1607             if (info->FileName[j-1] == '/') { break; }
1608             j--;
1609             }
1610           if (m+j+1 > outputsize)
1611             {
1612             outputsize += m+j+1;
1613             output = (char *)realloc(output, outputsize);
1614             }
1615           if (j > 0)
1616             {
1617             strncpy(output, info->FileName, j);
1618             }
1619           strncpy(&output[j], filename, m);
1620           output[j+m] = '\0';
1621           }
1622         else
1623           {
1624           if (m+1 > outputsize)
1625             {
1626             outputsize += m+1;
1627             output = (char *)realloc(output, outputsize);
1628             }
1629           strncpy(output, filename, m);
1630           output[m] = '\0';
1631           }
1632         }
1633       /* check all the search paths */
1634       else
1635         {
1636         directory = info->IncludeDirectories[i-1+system_first];
1637         j = strlen(directory);
1638         if (j + m + 2 > outputsize)
1639           {
1640           outputsize += j+m+2;
1641           output = (char *)realloc(output, outputsize);
1642           }
1643
1644         strncpy(output, directory, j);
1645         if (directory[j-1] != '/') { output[j++] = '/'; }
1646         strncpy(&output[j], filename, m);
1647         output[j+m] = '\0';
1648         }
1649
1650       if (count == 0)
1651         {
1652         nn = info->NumberOfIncludeFiles;
1653         for (ii = 0; ii < nn; ii++)
1654           {
1655           if (strcmp(output, info->IncludeFiles[ii]) == 0)
1656             {
1657             free(output);
1658             return info->IncludeFiles[ii];
1659             }
1660           }
1661         }
1662       else if (stat(output, &fs) == 0)
1663         {
1664         nn = info->NumberOfIncludeFiles;
1665         info->IncludeFiles = (const char **)preproc_array_check(
1666           (char **)info->IncludeFiles, sizeof(char *), nn);
1667         info->IncludeFiles[info->NumberOfIncludeFiles++] =
1668           vtkParse_CacheString(info->Strings, output, strlen(output));
1669         free(output);
1670         return info->IncludeFiles[nn];
1671         }
1672       }
1673     }
1674
1675   free(output);
1676   return NULL;
1677 }
1678
1679 /**
1680  * Convert a raw string into a normal string.  This is a helper
1681  * function for preproc_include_file() to allow raw strings to
1682  * be used in preprocessor directives.
1683  */
1684 void preproc_escape_string(
1685   char **linep, size_t *linelenp, size_t *jp, size_t d, size_t dl)
1686 {
1687   char *line = *linep;
1688   char *r = 0;
1689   size_t linelen = *linelenp;
1690   size_t l = *jp - d - 2*dl - 2;
1691   size_t i;
1692   size_t j = d;
1693
1694   if (l != 0)
1695     {
1696     r = (char *)malloc(l);
1697     memcpy(r, &line[j+dl+1], l);
1698     }
1699
1700   /* remove the "R" prefix */
1701   if (j >= 2 && line[j-1] == '\"' && line[j-2] == 'R')
1702     {
1703     line[j - 2] = '\"';
1704     j--;
1705     }
1706
1707   for (i = 0; i < l; i++)
1708     {
1709     /* expand line buffer as necessary */
1710     while (j+4 > linelen)
1711       {
1712       linelen *= 2;
1713       line = (char *)realloc(line, linelen);
1714       }
1715
1716     if ((r[i] >= ' ' && r[i] <= '~') || (r[i] & 0x80) != 0)
1717       {
1718       line[j++] = r[i];
1719       }
1720     else switch (r[i])
1721       {
1722       case '\a': line[j++] = '\\'; line[j++] = 'a'; break;
1723       case '\b': line[j++] = '\\'; line[j++] = 'b'; break;
1724       case '\f': line[j++] = '\\'; line[j++] = 'f'; break;
1725       case '\n': line[j++] = '\\'; line[j++] = 'n'; break;
1726       case '\r': line[j++] = '\\'; line[j++] = 'r'; break;
1727       case '\t': line[j++] = '\\'; line[j++] = 't'; break;
1728       case '\v': line[j++] = '\\'; line[j++] = 'v'; break;
1729       case '\\': line[j++] = '\\'; line[j++] = '\\'; break;
1730       case '\'': line[j++] = '\\'; line[j++] = '\''; break;
1731       case '\"': line[j++] = '\\'; line[j++] = '\"'; break;
1732       default:
1733         sprintf(&line[j], "\\%3.3o", r[i]);
1734         j += 4;
1735         break;
1736       }
1737     }
1738
1739   free(r);
1740   *linep = line;
1741   *linelenp = linelen;
1742   *jp = j;
1743 }
1744
1745 /**
1746  * Include a file.  All macros defined in the included file
1747  * will have their IsExternal flag set.
1748  */
1749 static int preproc_include_file(
1750   PreprocessInfo *info, const char *filename, int system_first)
1751 {
1752   const char *switchchars = "\n\r\"\'\?\\/*()";
1753   char switchchar[256];
1754   char *tbuf;
1755   size_t tbuflen = FILE_BUFFER_SIZE;
1756   char *line;
1757   size_t linelen = 80;
1758   size_t i, j, n, r;
1759   size_t d = 0;
1760   size_t dn = 0;
1761   int state = 0;
1762   int result = VTK_PARSE_OK;
1763   FILE *fp = NULL;
1764   const char *path = NULL;
1765   const char *save_filename;
1766   int save_external;
1767
1768   /* check to see if the file has aleady been included */
1769   path = preproc_find_include_file(info, filename, system_first, 1);
1770   if (path != 0)
1771     {
1772 #if PREPROC_DEBUG
1773     int k = 0;
1774     while (filename[k] != '>' && filename[k] != '\"' &&
1775            filename[k] != '\n' && filename[k] != '\0') { k++; }
1776     if (filename[k] == '>')
1777       fprintf(stderr, "already loaded file <%*.*s>\n", k, k, filename);
1778     else
1779       fprintf(stderr, "already loaded file \"%*.*s\"\n", k, k, filename);
1780 #endif
1781
1782     return VTK_PARSE_OK;
1783     }
1784   /* go to the filesystem */
1785   path = preproc_find_include_file(info, filename, system_first, 0);
1786   if (path == NULL)
1787     {
1788 #if PREPROC_DEBUG
1789     int k = 0;
1790     while (filename[k] != '>' && filename[k] != '\"' &&
1791            filename[k] != '\n' && filename[k] != '\0') { k++; }
1792     if (filename[k] == '>')
1793       fprintf(stderr, "couldn't find file <%*.*s>\n", k, k, filename);
1794     else
1795       fprintf(stderr, "couldn't find file \"%*.*s\"\n", k, k, filename);
1796 #endif
1797     return VTK_PARSE_FILE_NOT_FOUND;
1798     }
1799
1800 #if PREPROC_DEBUG
1801   fprintf(stderr, "including file %s\n", path);
1802 #endif
1803   fp = fopen(path, "r");
1804
1805   if (fp == NULL)
1806     {
1807 #if PREPROC_DEBUG
1808     fprintf(stderr, "couldn't open file %s\n", path);
1809 #endif
1810     return VTK_PARSE_FILE_OPEN_ERROR;
1811     }
1812
1813   save_external = info->IsExternal;
1814   save_filename = info->FileName;
1815   info->IsExternal = 1;
1816   info->FileName = path;
1817
1818   /* make a table of interesting characters */
1819   memset(switchchar, '\0', 256);
1820   n = strlen(switchchars) + 1;
1821   for (i = 0; i < n; i++)
1822     {
1823     switchchar[(unsigned char)(switchchars[i])] = 1;
1824     }
1825
1826   tbuf = (char *)malloc(tbuflen+4);
1827   line = (char *)malloc(linelen);
1828
1829   /* the buffer must hold a whole line for it to be processed */
1830   j = 0;
1831   i = 0;
1832   n = 0;
1833   r = 0;
1834
1835   do
1836     {
1837     if (i >= n)
1838       {
1839       /* recycle unused lookahead chars */
1840       if (r)
1841         {
1842         r = n + 2 - i;
1843         if (r == 2)
1844           {
1845           tbuf[0] = tbuf[tbuflen-2];
1846           tbuf[1] = tbuf[tbuflen-1];
1847           }
1848         else if (r == 1)
1849           {
1850           tbuf[0] = tbuf[tbuflen-1];
1851           }
1852         }
1853
1854       /* read the next chunk of the file */
1855       i = 0;
1856       if (feof(fp))
1857         {
1858         /* still have the lookahead chars left */
1859         n = r;
1860         r = 0;
1861         }
1862       else
1863         {
1864         /* fill the remainder of the buffer */
1865         errno = 0;
1866         tbuflen = r + FILE_BUFFER_SIZE;
1867         while ((n = fread(&tbuf[r], 1, tbuflen-r, fp)) == 0 && ferror(fp))
1868           {
1869           if (errno != EINTR)
1870             {
1871             fclose(fp);
1872             free(tbuf);
1873             free(line);
1874             info->IsExternal = save_external;
1875             return VTK_PARSE_FILE_READ_ERROR;
1876             }
1877           errno = 0;
1878           clearerr(fp);
1879           }
1880
1881         if (n + r < tbuflen)
1882           {
1883           /* this only occurs if the final fread does not fill the buffer */
1884           n += r;
1885           r = 0;
1886           }
1887         else
1888           {
1889           /* set a lookahead reserve of two chars */
1890           n -= (2 - r);
1891           r = 2;
1892           }
1893
1894         /* guard against lookahead past last char in file */
1895         tbuf[n + r] = '\0';
1896         }
1897       }
1898
1899     /* copy the characters until end of line is found */
1900     while (i < n)
1901       {
1902       /* expand line buffer as necessary */
1903       while (j+4 > linelen)
1904         {
1905         linelen *= 2;
1906         line = (char *)realloc(line, linelen);
1907         }
1908
1909       /* check for uninteresting characters first */
1910       if (!switchchar[(unsigned char)(tbuf[i])])
1911         {
1912         line[j++] = tbuf[i++];
1913         }
1914       else if (state == '(')
1915         {
1916         /* look for end of raw string delimiter */
1917         if (tbuf[i] == '(')
1918           {
1919           dn = j - d;
1920           state = ')';
1921           }
1922         line[j++] = tbuf[i++];
1923         }
1924       else if (state == ')')
1925         {
1926         /* look for end of raw string */
1927         if (tbuf[i] == '\"')
1928           {
1929           if ((j - d) > 2*dn+1 && line[j-dn-1] == ')' &&
1930               strncmp(&line[d], &line[j-dn], dn) == 0)
1931             {
1932             preproc_escape_string(&line, &linelen, &j, d, dn);
1933             state = 0;
1934             }
1935           }
1936         line[j++] = tbuf[i++];
1937         }
1938 #ifdef PREPROC_TRIGRAPHS
1939       else if (tbuf[i] == '?' && tbuf[i+1] == '?')
1940         {
1941         i += 2;
1942         switch (tbuf[i])
1943           {
1944           case '=': tbuf[i] = '#'; break;
1945           case '/': tbuf[i] = '\\'; break;
1946           case '\'': tbuf[i] = '^'; break;
1947           case '(': tbuf[i] = '['; break;
1948           case ')': tbuf[i] = ']'; break;
1949           case '!': tbuf[i] = '|'; break;
1950           case '<': tbuf[i] = '{'; break;
1951           case '>': tbuf[i] = '}'; break;
1952           case '-': tbuf[i] = '~'; break;
1953           default: line[j++] = tbuf[--i];
1954           }
1955         }
1956 #endif
1957       else if (tbuf[i] == '\\' && tbuf[i+1] == '\n')
1958         {
1959         i += 2;
1960         }
1961       else if (tbuf[i] == '\\' && tbuf[i+1] == '\r' && tbuf[i+2] == '\n')
1962         {
1963         i += 3;
1964         }
1965       else if (tbuf[i] == '\r' && tbuf[i+1] == '\n')
1966         {
1967         i++;
1968         }
1969       else if (state == '*')
1970         {
1971         if (tbuf[i] == '*' && tbuf[i+1] == '/')
1972           {
1973           line[j++] = tbuf[i++];
1974           line[j++] = tbuf[i++];
1975           state = 0;
1976           }
1977         else
1978           {
1979           line[j++] = tbuf[i++];
1980           }
1981         }
1982       else if (state == '/' && tbuf[i] != '\n')
1983         {
1984         line[j++] = tbuf[i++];
1985         }
1986       else if (state == '\'' || state == '\"')
1987         {
1988         if (tbuf[i] == state)
1989           {
1990           line[j++] = tbuf[i++];
1991           state = 0;
1992           }
1993         else if (tbuf[i] == '\\' && tbuf[i+1] != '\0')
1994           {
1995           line[j++] = tbuf[i++];
1996           line[j++] = tbuf[i++];
1997           }
1998         else
1999           {
2000           line[j++] = tbuf[i++];
2001           }
2002         }
2003       else if (tbuf[i] == '/')
2004         {
2005         if (tbuf[i+1] == '*' || tbuf[i+1] == '/')
2006           {
2007           state = tbuf[i+1];
2008           line[j++] = tbuf[i++];
2009           }
2010         line[j++] = tbuf[i++];
2011         }
2012       else if (tbuf[i] == '\"' || tbuf[i] == '\'')
2013         {
2014         state = tbuf[i];
2015         /* check for raw string prefixes */
2016         if (state == '\"' && j > 0 && line[j-1] == 'R' &&
2017             ((j > 2 &&
2018               (line[j-3] == 'u' || line[j-2] == '8') &&
2019               (j == 3 ||
2020                !vtkParse_CharType(line[j-4], CPRE_IDGIT|CPRE_QUOTE))) ||
2021              (j > 1 &&
2022               (line[j-2] == 'u' || line[j-2] == 'U' || line[j-2] == 'L') &&
2023               (j == 2 ||
2024                !vtkParse_CharType(line[j-3], CPRE_IDGIT|CPRE_QUOTE))) ||
2025              (j == 1 ||
2026               !vtkParse_CharType(line[j-2], CPRE_IDGIT|CPRE_QUOTE))))
2027           {
2028           state = '(';
2029           d = j + 1;
2030           }
2031         line[j++] = tbuf[i++];
2032         }
2033       else if (tbuf[i] != '\n' && tbuf[i] != '\0')
2034         {
2035         line[j++] = tbuf[i++];
2036         }
2037       else
2038         {
2039         line[j++] = tbuf[i++];
2040         break;
2041         }
2042       }
2043
2044     if (i < n || n == 0)
2045       {
2046       const char *cp = line;
2047       line[j] = '\0';
2048       j = 0;
2049       cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2050       if (*cp == '#')
2051         {
2052         vtkParsePreprocess_HandleDirective(info, line);
2053         }
2054       }
2055     }
2056   while (n > 0);
2057
2058   free(tbuf);
2059   free(line);
2060   fclose(fp);
2061
2062   info->IsExternal = save_external;
2063   info->FileName = save_filename;
2064
2065   return result;
2066 }
2067
2068 /**
2069  * Handle the #include directive.  The header file will
2070  * only go through the preprocessor.
2071  */
2072 static int preproc_evaluate_include(
2073   PreprocessInfo *info, StringTokenizer *tokens)
2074 {
2075   const char *cp;
2076   const char *filename;
2077
2078   if (tokens->hash == HASH_INCLUDE)
2079     {
2080     vtkParse_NextToken(tokens);
2081
2082     cp = tokens->text;
2083
2084     if (tokens->tok == TOK_ID)
2085       {
2086       MacroInfo *macro = preproc_find_macro(info, tokens);
2087       if (macro && !macro->IsExcluded && macro->Definition)
2088         {
2089         cp = macro->Definition;
2090         }
2091       else
2092         {
2093 #if PREPROC_DEBUG
2094         fprintf(stderr, "couldn't find macro %*.*s.\n",
2095                 (int)tokens->len, (int)tokens->len, tokens->text);
2096 #endif
2097         return VTK_PARSE_MACRO_UNDEFINED;
2098         }
2099       }
2100
2101     if (*cp == '\"')
2102       {
2103       filename = cp + 1;
2104       cp += vtkParse_SkipQuotes(cp);
2105       if (cp <= filename + 1 || *(cp-1) != '\"')
2106         {
2107         return VTK_PARSE_SYNTAX_ERROR;
2108         }
2109
2110       return preproc_include_file(info, filename, 0);
2111       }
2112     else if (*cp == '<')
2113       {
2114       cp++;
2115       filename = cp;
2116       while (*cp != '>' && *cp != '\n' && *cp != '\0') { cp++; }
2117       if (*cp != '>')
2118         {
2119         return VTK_PARSE_SYNTAX_ERROR;
2120         }
2121
2122       return preproc_include_file(info, filename, 1);
2123       }
2124     }
2125
2126   return VTK_PARSE_OK;
2127 }
2128
2129 /**
2130  * Handle any recognized directive.
2131  * Unrecognized directives are ignored.
2132  */
2133 int vtkParsePreprocess_HandleDirective(
2134   PreprocessInfo *info, const char *directive)
2135 {
2136   int result = VTK_PARSE_OK;
2137   StringTokenizer tokens;
2138
2139   vtkParse_InitTokenizer(&tokens, directive, WS_PREPROC);
2140
2141   if (tokens.tok != '#')
2142     {
2143     return VTK_PARSE_SYNTAX_ERROR;
2144     }
2145
2146   vtkParse_NextToken(&tokens);
2147
2148   if (tokens.tok == TOK_ID)
2149     {
2150     if ((tokens.hash == HASH_IFDEF && tokens.len == 5 &&
2151          strncmp("ifdef", tokens.text, tokens.len) == 0) ||
2152         (tokens.hash == HASH_IFNDEF && tokens.len == 6 &&
2153          strncmp("ifndef", tokens.text, tokens.len) == 0) ||
2154         (tokens.hash == HASH_IF && tokens.len == 2 &&
2155          strncmp("if", tokens.text, tokens.len) == 0) ||
2156         (tokens.hash == HASH_ELIF && tokens.len == 4 &&
2157          strncmp("elif", tokens.text, tokens.len) == 0) ||
2158         (tokens.hash == HASH_ELSE && tokens.len == 4 &&
2159          strncmp("else", tokens.text, tokens.len) == 0) ||
2160         (tokens.hash == HASH_ENDIF && tokens.len == 5 &&
2161          strncmp("endif", tokens.text, tokens.len) == 0))
2162       {
2163       result = preproc_evaluate_if(info, &tokens);
2164       while (tokens.tok) { vtkParse_NextToken(&tokens); }
2165 #if PREPROC_DEBUG
2166         {
2167         size_t n = tokens.text - directive;
2168
2169         if (result == VTK_PARSE_SKIP)
2170           {
2171           fprintf(stderr, "SKIP: ");
2172           }
2173         else if (result == VTK_PARSE_OK)
2174           {
2175           fprintf(stderr, "READ: ");
2176           }
2177         else
2178           {
2179           fprintf(stderr, "ERR%-2.2d ", result);
2180           }
2181         fprintf(stderr, "%*.*s\n", (int)n, (int)n, directive);
2182         }
2183 #endif
2184       }
2185     else if (info->ConditionalDepth == 0)
2186       {
2187       if ((tokens.hash == HASH_DEFINE && tokens.len == 6 &&
2188            strncmp("define", tokens.text, tokens.len) == 0) ||
2189           (tokens.hash == HASH_UNDEF && tokens.len == 5 &&
2190            strncmp("undef", tokens.text, tokens.len) == 0))
2191         {
2192         result = preproc_evaluate_define(info, &tokens);
2193         }
2194       else if (tokens.hash == HASH_INCLUDE && tokens.len == 7 &&
2195                strncmp("include", tokens.text, tokens.len) == 0)
2196         {
2197         result = preproc_evaluate_include(info, &tokens);
2198         }
2199       }
2200     }
2201
2202   if (info->ConditionalDepth > 0)
2203     {
2204     return VTK_PARSE_SKIP;
2205     }
2206
2207   return result;
2208 }
2209
2210 /**
2211  * Evaluate a preprocessor expression.
2212  * If no errors occurred, the result will be VTK_PARSE_OK.
2213  */
2214 int vtkParsePreprocess_EvaluateExpression(
2215   PreprocessInfo *info, const char *text,
2216   preproc_int_t *val, int *is_unsigned)
2217 {
2218   StringTokenizer tokens;
2219   vtkParse_InitTokenizer(&tokens, text, WS_PREPROC);
2220
2221   return preproc_evaluate_expression(info, &tokens, val, is_unsigned);
2222 }
2223
2224 /** Add a macro for defining a macro */
2225 #define PREPROC_MACRO_TO_STRING2(x) #x
2226 #define PREPROC_MACRO_TO_STRING(x) PREPROC_MACRO_TO_STRING2(x)
2227 #define PREPROC_ADD_MACRO(info, x) \
2228 preproc_add_macro_definition(info, #x, PREPROC_MACRO_TO_STRING2(x))
2229
2230 /**
2231  * Add all standard preprocessory macros.  Specify the platform.
2232  */
2233 void vtkParsePreprocess_AddStandardMacros(
2234   PreprocessInfo *info, int platform)
2235 {
2236   int save_external = info->IsExternal;
2237   info->IsExternal = 1;
2238
2239   /* a special macro to indicate that this is the wrapper */
2240   preproc_add_macro_definition(info, "__WRAP__", "1");
2241
2242   /* language macros - assume that we are wrapping C++ code */
2243   preproc_add_macro_definition(info, "__cplusplus", "1");
2244
2245   /* stdc version macros */
2246 #ifdef __STDC__
2247   PREPROC_ADD_MACRO(info, __STDC__);
2248 #endif
2249 #ifdef __STDC_VERSION__
2250   PREPROC_ADD_MACRO(info, __STDC_VERSION__);
2251 #endif
2252 #ifdef __STDC_HOSTED__
2253   PREPROC_ADD_MACRO(info, __STDC_HOSTED__);
2254 #endif
2255
2256   if (platform == VTK_PARSE_NATIVE)
2257     {
2258 #ifdef WIN32
2259     PREPROC_ADD_MACRO(info, WIN32);
2260 #endif
2261 #ifdef _WIN32
2262     PREPROC_ADD_MACRO(info, _WIN32);
2263 #endif
2264 #ifdef _MSC_VER
2265     PREPROC_ADD_MACRO(info, _MSC_VER);
2266 #endif
2267
2268 #ifdef __BORLAND__
2269     PREPROC_ADD_MACRO(info, __BORLAND__);
2270 #endif
2271
2272 #ifdef __CYGWIN__
2273     PREPROC_ADD_MACRO(info, __CYGWIN__);
2274 #endif
2275 #ifdef MINGW
2276     PREPROC_ADD_MACRO(info, MINGW);
2277 #endif
2278 #ifdef __MINGW32__
2279     PREPROC_ADD_MACRO(info, __MINGW32__);
2280 #endif
2281
2282 #ifdef __linux__
2283     PREPROC_ADD_MACRO(info, __linux__);
2284 #endif
2285 #ifdef __LINUX__
2286     PREPROC_ADD_MACRO(info, __LINUX__);
2287 #endif
2288
2289 #ifdef __APPLE__
2290     PREPROC_ADD_MACRO(info, __APPLE__);
2291 #endif
2292 #ifdef __MACH__
2293     PREPROC_ADD_MACRO(info, __MACH__);
2294 #endif
2295 #ifdef __DARWIN__
2296     PREPROC_ADD_MACRO(info, __DARWIN__);
2297 #endif
2298
2299 #ifdef __GNUC__
2300     PREPROC_ADD_MACRO(info, __GNUC__);
2301 #endif
2302 #ifdef __LP64__
2303     PREPROC_ADD_MACRO(info, __LP64__);
2304 #endif
2305 #ifdef __BIG_ENDIAN__
2306     PREPROC_ADD_MACRO(info, __BIG_ENDIAN__);
2307 #endif
2308 #ifdef __LITTLE_ENDIAN__
2309     PREPROC_ADD_MACRO(info, __LITTLE_ENDIAN__);
2310 #endif
2311     }
2312
2313   info->IsExternal = save_external;
2314 }
2315
2316 /**
2317  * Add a preprocessor macro, including a definition.
2318  */
2319 int vtkParsePreprocess_AddMacro(
2320   PreprocessInfo *info, const char *name, const char *definition)
2321 {
2322   StringTokenizer token;
2323   MacroInfo **macro_p;
2324   MacroInfo *macro;
2325
2326   vtkParse_InitTokenizer(&token, name, WS_PREPROC);
2327   macro_p = preproc_macro_location(info, &token, 1);
2328   if (*macro_p)
2329     {
2330     macro = *macro_p;
2331     if (preproc_identical(macro->Definition, definition))
2332       {
2333       return VTK_PARSE_OK;
2334       }
2335     else
2336       {
2337       return VTK_PARSE_MACRO_REDEFINED;
2338       }
2339     }
2340
2341   macro = preproc_new_macro(info, name, definition);
2342   macro->IsExternal = 1;
2343   *macro_p = macro;
2344
2345   return VTK_PARSE_OK;
2346 }
2347
2348 /**
2349  * Return a preprocessor macro struct, or NULL if not found.
2350  */
2351 MacroInfo *vtkParsePreprocess_GetMacro(
2352   PreprocessInfo *info, const char *name)
2353 {
2354   StringTokenizer token;
2355   MacroInfo *macro;
2356
2357   vtkParse_InitTokenizer(&token, name, WS_PREPROC);
2358   macro = preproc_find_macro(info, &token);
2359
2360   if (macro && !macro->IsExcluded)
2361     {
2362     return macro;
2363     }
2364
2365   return NULL;
2366 }
2367
2368 /**
2369  * Remove a preprocessor macro.
2370  */
2371 int vtkParsePreprocess_RemoveMacro(
2372   PreprocessInfo *info, const char *name)
2373 {
2374   StringTokenizer token;
2375
2376   vtkParse_InitTokenizer(&token, name, WS_PREPROC);
2377
2378   if (preproc_remove_macro(info, &token))
2379     {
2380     return VTK_PARSE_OK;
2381     }
2382
2383   return VTK_PARSE_MACRO_UNDEFINED;
2384 }
2385
2386 /**
2387  * Expand a macro, argstring is ignored if not a function macro
2388  */
2389 const char *vtkParsePreprocess_ExpandMacro(
2390   PreprocessInfo *info, MacroInfo *macro, const char *argstring)
2391 {
2392   const char *cp = argstring;
2393   int n = 0;
2394   int j = 0;
2395   const char *stack_values[8];
2396   const char **values = NULL;
2397   const char *pp = NULL;
2398   const char *dp = NULL;
2399   const char *wp = NULL;
2400   char stack_rp[128];
2401   char *rp = NULL;
2402   size_t rs = 0;
2403   size_t i = 0;
2404   size_t l = 0;
2405   size_t k = 0;
2406   int stringify = 0;
2407   int noexpand = 0;
2408   int empty_variadic = 0;
2409   int depth = 1;
2410   int c;
2411
2412   if (macro->IsFunction)
2413     {
2414     if (argstring == NULL || *cp != '(')
2415       {
2416       return NULL;
2417       }
2418
2419     /* break the string into individual argument values */
2420     values = stack_values;
2421
2422     cp++;
2423     values[n++] = cp;
2424     while (depth > 0 && *cp != '\0')
2425       {
2426       while (*cp != '\0')
2427         {
2428         if (*cp == '\"' || *cp == '\'')
2429           {
2430           cp += vtkParse_SkipQuotes(cp);
2431           }
2432         else if (cp[0] == '/' && (cp[1] == '*' || cp[1] == '/'))
2433           {
2434           cp += vtkParse_SkipComment(cp);
2435           }
2436         else if (*cp == '(')
2437           {
2438           cp++;
2439           depth++;
2440           }
2441         else if (*cp == ')')
2442           {
2443           cp++;
2444           if (--depth == 0)
2445             {
2446             break;
2447             }
2448           }
2449         else if (*cp == ',')
2450           {
2451           cp++;
2452           if (depth == 1)
2453             {
2454             break;
2455             }
2456           }
2457         else if (*cp != '\0')
2458           {
2459           cp++;
2460           }
2461         }
2462       if (n >= 8 && (n & (n-1)) == 0)
2463         {
2464         if (values != stack_values)
2465           {
2466           values = (const char **)realloc(
2467             (char **)values, 2*n*sizeof(const char **));
2468           }
2469         else
2470           {
2471           values = (const char **)malloc(2*n*sizeof(const char **));
2472           memcpy((char **)values, stack_values, 8*sizeof(const char **));
2473           }
2474         }
2475
2476       values[n++] = cp;
2477       }
2478     --n;
2479
2480     /* diagnostic: print out the values */
2481 #if PREPROC_DEBUG
2482     for (j = 0; j < n; j++)
2483       {
2484       size_t m = values[j+1] - values[j] - 1;
2485       fprintf(stderr, "arg %i: %*.*s\n",
2486               (int)j, (int)m, (int)m, values[j]);
2487       }
2488 #endif
2489
2490     /* one arg that is only whitespace can also be no args*/
2491     if (macro->NumberOfParameters == 0 && n == 1)
2492       {
2493       const char *tp = values[0];
2494       tp += vtkParse_SkipWhitespace(tp, WS_PREPROC);
2495       if (tp + 1 >= values[1])
2496         {
2497         n = 0;
2498         }
2499       }
2500
2501     /* allow the variadic arg to be empty */
2502     if (macro->IsVariadic && n == macro->NumberOfParameters-1)
2503       {
2504       empty_variadic = 1;
2505       }
2506
2507     /* check for correct number of arguments */
2508     if (n < (macro->NumberOfParameters - empty_variadic) ||
2509         (n > macro->NumberOfParameters && !macro->IsVariadic))
2510       {
2511       if (values != stack_values) { free((char **)values); }
2512 #if PREPROC_DEBUG
2513       fprintf(stderr, "wrong number of macro args to %s, %lu != %lu\n",
2514               macro->Name, n, macro->NumberOfParameters);
2515 #endif
2516       return NULL;
2517       }
2518     }
2519
2520   cp = macro->Definition;
2521   cp = (cp ? cp : "");
2522   dp = cp;
2523   rp = stack_rp;
2524   rp[0] = '\0';
2525   rs = 128;
2526
2527   while (*cp != '\0')
2528     {
2529     pp = cp;
2530     wp = cp;
2531     stringify = 0;
2532     noexpand = 0;
2533     /* skip all chars that aren't part of a name */
2534     while (!vtkParse_CharType(*cp, CPRE_ID) && *cp != '\0')
2535       {
2536       dp = cp;
2537       cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2538       if (cp > dp)
2539         {
2540         dp = cp;
2541         }
2542       else if (vtkParse_CharType(*cp, CPRE_QUOTE))
2543         {
2544         cp += vtkParse_SkipQuotes(cp);
2545         dp = cp;
2546         wp = cp;
2547         noexpand = 0;
2548         }
2549       else if (vtkParse_CharType(*cp, CPRE_DIGIT))
2550         {
2551         cp += vtkParse_SkipNumber(cp);
2552         dp = cp;
2553         wp = cp;
2554         noexpand = 0;
2555         }
2556       else if (cp[0] == '#' && cp[1] == '#')
2557         {
2558         noexpand = 1;
2559         dp = wp;
2560         cp += 2;
2561         wp = cp;
2562         cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2563         break;
2564         }
2565       else if (*cp == '#')
2566         {
2567         stringify = 1;
2568         dp = cp;
2569         wp = cp;
2570         cp++;
2571         cp += vtkParse_SkipWhitespace(cp, WS_PREPROC);
2572         break;
2573         }
2574       else
2575         {
2576         cp++;
2577         dp = cp;
2578         wp = cp;
2579         }
2580       }
2581     l = dp - pp;
2582     if (l > 0)
2583       {
2584       if (i + l + 1 >= rs)
2585         {
2586         rs += rs + i + l + 1;
2587         if (rp != stack_rp)
2588           {
2589           rp = (char *)realloc(rp, rs);
2590           }
2591         else
2592           {
2593           rp = (char *)malloc(rs);
2594           memcpy(rp, stack_rp, i);
2595           }
2596         }
2597       strncpy(&rp[i], pp, l);
2598       i += l;
2599       rp[i] = '\0';
2600       }
2601
2602     /* get the name */
2603     pp = cp;
2604     l = vtkParse_SkipId(cp);
2605     cp += l;
2606     if (l > 0)
2607       {
2608       for (j = 0; j < macro->NumberOfParameters; j++)
2609         {
2610         /* check whether the name matches a parameter */
2611         if (strncmp(pp, macro->Parameters[j], l) == 0 &&
2612             macro->Parameters[j][l] == '\0')
2613           {
2614           if (macro->IsVariadic && j == macro->NumberOfParameters-1)
2615             {
2616             /* if variadic arg, use all remaining args */
2617             pp = values[j] - empty_variadic;
2618             l = values[n] - pp - 1;
2619             }
2620           else
2621             {
2622             /* else just get one arg */
2623             pp = values[j];
2624             l = values[j+1] - pp - 1;
2625             }
2626           /* remove leading whitespace from argument */
2627           c = *pp;
2628           while (vtkParse_CharType(c, CPRE_WHITE))
2629             {
2630             c = *(++pp);
2631             l--;
2632             }
2633           /* remove trailing whitespace from argument */
2634           if (l > 0)
2635             {
2636             c = pp[l - 1];
2637             while (vtkParse_CharType(c, CPRE_WHITE))
2638               {
2639               if (--l == 0)
2640                 {
2641                 break;
2642                 }
2643               c = pp[l-1];
2644               }
2645             }
2646           /* check if followed by "##" */
2647           wp = cp;
2648           wp += vtkParse_SkipWhitespace(wp, WS_PREPROC);
2649           if (wp[0] == '#' && wp[1] == '#')
2650             {
2651             noexpand = 1;
2652             }
2653           break;
2654           }
2655         }
2656       if (stringify)
2657         {
2658         /* compute number of chars that will be added */
2659         stringify = 2;
2660         for (k = 0; k < l; k++)
2661           {
2662           c = pp[k];
2663           if (c == '\\' || c == '\"')
2664             {
2665             stringify++;
2666             }
2667           }
2668         }
2669       if (i + l + stringify + 1 >= rs)
2670         {
2671         rs += rs + i + l + 1;
2672         if (rp != stack_rp)
2673           {
2674           rp = (char *)realloc(rp, rs);
2675           }
2676         else
2677           {
2678           rp = (char *)malloc(rs);
2679           memcpy(rp, stack_rp, i);
2680           }
2681         }
2682       if (stringify)
2683         {
2684         /* convert argument into a string, due to "#" */
2685         rp[i++] = '\"';
2686         for (k = 0; k < l; k++)
2687           {
2688           c = pp[k];
2689           if (c == '\\' || c == '\"')
2690             {
2691             rp[i++] = '\\';
2692             }
2693           rp[i++] = c;
2694           }
2695         rp[i++] = '\"';
2696         }
2697       else if (empty_variadic && j == macro->NumberOfParameters-1)
2698         {
2699         /* remove trailing comma before empty variadic (non-standard) */
2700         k = i;
2701         if (k > 0)
2702           {
2703           do
2704             {
2705             c = rp[--k];
2706             }
2707           while (k > 0 && vtkParse_CharType(c, CPRE_WHITE));
2708           if (rp[k] == ',')
2709             {
2710             i = k;
2711             }
2712           }
2713         }
2714       else if (noexpand)
2715         {
2716         /* do not expand args that will be concatenated with "##" */
2717         strncpy(&rp[i], pp, l);
2718         i += l;
2719         }
2720       else
2721         {
2722         /* process the arguments before substituting them */
2723         const char *text;
2724         int is_excluded = macro->IsExcluded;
2725         macro->IsExcluded = 1;
2726         strncpy(&rp[i], pp, l);
2727         rp[i + l] = '\0';
2728         text = vtkParsePreprocess_ProcessString(info, &rp[i]);
2729         if (text)
2730           {
2731           l = strlen(text);
2732           if (text != &rp[i])
2733             {
2734             char *tp = NULL;
2735             if (i + l + 1 >= rs)
2736               {
2737               rs += rs + i + l + 1;
2738               tp = rp;
2739               rp = (char *)malloc(rs);
2740               memcpy(rp, tp, i);
2741               }
2742             strncpy(&rp[i], text, l);
2743             vtkParsePreprocess_FreeProcessedString(info, text);
2744             if (tp && tp != stack_rp)
2745               {
2746               free(tp);
2747               }
2748             }
2749           }
2750         macro->IsExcluded = is_excluded;
2751         i += l;
2752         }
2753       rp[i] = '\0';
2754       }
2755     }
2756
2757   if (values != stack_values) { free((char **)values); }
2758
2759   if (!macro->IsFunction && macro->Definition &&
2760       strcmp(rp, macro->Definition) == 0)
2761     {
2762     if (rp != stack_rp) { free(rp); }
2763     return macro->Definition;
2764     }
2765
2766   if (rp == stack_rp)
2767     {
2768     rp = (char *)malloc(strlen(stack_rp) + 1);
2769     strcpy(rp, stack_rp);
2770     }
2771
2772   return rp;
2773 }
2774
2775 /**
2776  * Process a string
2777  */
2778 const char *vtkParsePreprocess_ProcessString(
2779   PreprocessInfo *info, const char *text)
2780 {
2781   char stack_rp[128];
2782   char *rp;
2783   char *ep;
2784   size_t i = 0;
2785   size_t rs = 128;
2786   int last_tok = 0;
2787   StringTokenizer tokens;
2788   vtkParse_InitTokenizer(&tokens, text, WS_PREPROC);
2789
2790   rp = stack_rp;
2791   rp[0] = '\0';
2792
2793   while (tokens.tok)
2794     {
2795     size_t l = tokens.len;
2796     size_t j;
2797     const char *cp = tokens.text;
2798     const char *dp;
2799
2800     if (tokens.tok == TOK_STRING && last_tok == TOK_STRING)
2801       {
2802       if (i > 0)
2803         {
2804         do { --i; } while (i > 0 && rp[i] != '\"');
2805         }
2806       while (*cp != '\"' && l > 1) { cp++; l--; }
2807       if (*cp == '\"' && l > 1) { cp++; l--; }
2808       }
2809
2810     if (i + l + 2 >= rs)
2811       {
2812       rs += rs + i + l + 2;
2813       if (rp == stack_rp)
2814         {
2815         rp = (char *)malloc(rs);
2816         memcpy(rp, stack_rp, i);
2817         }
2818       else
2819         {
2820         rp = (char *)realloc(rp, rs);
2821         }
2822       }
2823
2824     /* copy the token, removing backslash-newline */
2825     dp = cp;
2826     ep = &rp[i];
2827     for (j = 0; j < l; j++)
2828       {
2829       if (*dp == '\\')
2830         {
2831         if (dp[1] == '\n') { dp += 2; }
2832         else if (dp[1] == '\r' && dp[2] == '\n') { dp += 3; }
2833         else { *ep++ = *dp++; }
2834         }
2835       else
2836         {
2837         *ep++ = *dp++;
2838         }
2839       }
2840     l = ep - &rp[i];
2841
2842     if (tokens.tok == TOK_ID)
2843       {
2844       MacroInfo *macro = preproc_find_macro(info, &tokens);
2845       if (macro && !macro->IsExcluded)
2846         {
2847         const char *args = NULL;
2848         int expand = 1;
2849
2850         if (macro->IsFunction)
2851           {
2852           /* expand function macros using the arguments */
2853           vtkParse_NextToken(&tokens);
2854           if (tokens.tok == '(')
2855             {
2856             int depth = 1;
2857             args = tokens.text;
2858             while (depth > 0 && vtkParse_NextToken(&tokens))
2859               {
2860               if (tokens.tok == '(')
2861                 {
2862                 depth++;
2863                 }
2864               else if (tokens.tok == ')')
2865                 {
2866                 depth--;
2867                 }
2868               }
2869             if (tokens.tok != ')')
2870               {
2871               if (rp != stack_rp) { free(rp); }
2872               return NULL;
2873               }
2874             }
2875           else
2876             {
2877             /* unput the last token if it isn't "(" */
2878             tokens.len = l;
2879             tokens.text = cp;
2880             expand = 0;
2881             }
2882           }
2883         if (expand)
2884           {
2885           const char *expansion;
2886           const char *processed;
2887           expansion = vtkParsePreprocess_ExpandMacro(info, macro, args);
2888           if (expansion == NULL)
2889             {
2890             if (rp != stack_rp) { free(rp); }
2891             return NULL;
2892             }
2893           macro->IsExcluded = 1;
2894           processed = vtkParsePreprocess_ProcessString(info, expansion);
2895           macro->IsExcluded = 0;
2896           if (processed == NULL)
2897             {
2898             vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
2899             if (rp != stack_rp) { free(rp); }
2900             return NULL;
2901             }
2902           l = strlen(processed);
2903           if (l > 0)
2904             {
2905             if (i + l + 2 >= rs)
2906               {
2907               rs += rs + i + l + 2;
2908               if (rp == stack_rp)
2909                 {
2910                 rp = (char *)malloc(rs);
2911                 memcpy(rp, stack_rp, i);
2912                 }
2913               else
2914                 {
2915                 rp = (char *)realloc(rp, rs);
2916                 }
2917               }
2918             strncpy(&rp[i], processed, l);
2919             }
2920           if (processed != expansion)
2921             {
2922             vtkParsePreprocess_FreeProcessedString(info, processed);
2923             }
2924           vtkParsePreprocess_FreeMacroExpansion(info, macro, expansion);
2925           }
2926         }
2927       }
2928
2929     i += l;
2930
2931     last_tok = tokens.tok;
2932     l = tokens.len;
2933     cp = tokens.text;
2934     if (vtkParse_NextToken(&tokens) && tokens.text > cp + l)
2935       {
2936       rp[i++] = ' ';
2937       }
2938     }
2939   rp[i] = '\0';
2940
2941   if (strcmp(rp, text) == 0)
2942     {
2943     /* no change, return */
2944     if (rp != stack_rp) { free(rp); }
2945     return text;
2946     }
2947   else
2948     {
2949     /* string changed, recursively reprocess */
2950     const char *tp = vtkParsePreprocess_ProcessString(info, rp);
2951     if (rp != tp)
2952       {
2953       if (rp != stack_rp) { free(rp); }
2954       return tp;
2955       }
2956     if (rp == stack_rp)
2957       {
2958       rp = (char *)malloc(strlen(stack_rp) + 1);
2959       strcpy(rp, stack_rp);
2960       }
2961     }
2962
2963   return rp;
2964 }
2965
2966 /**
2967  * Free a string returned by ExpandMacro
2968  */
2969 void vtkParsePreprocess_FreeMacroExpansion(
2970   PreprocessInfo *info, MacroInfo *macro, const char *text)
2971 {
2972   /* only free expansion if it is different from definition */
2973   if (info && text != macro->Definition)
2974     {
2975     free((char *)text);
2976     }
2977 }
2978
2979 /**
2980  * Free a string returned by ProcessString
2981  */
2982 void vtkParsePreprocess_FreeProcessedString(
2983   PreprocessInfo *info, const char *text)
2984 {
2985   if (info)
2986     {
2987     free((char *)text);
2988     }
2989 }
2990
2991 /**
2992  * Add an include directory.
2993  */
2994 void vtkParsePreprocess_IncludeDirectory(
2995   PreprocessInfo *info, const char *name)
2996 {
2997   int i, n;
2998
2999   n = info->NumberOfIncludeDirectories;
3000   for (i = 0; i < n; i++)
3001     {
3002     if (strcmp(name, info->IncludeDirectories[i]) == 0)
3003       {
3004       return;
3005       }
3006     }
3007
3008   info->IncludeDirectories = (const char **)preproc_array_check(
3009     (char **)info->IncludeDirectories, sizeof(char *),
3010     info->NumberOfIncludeDirectories);
3011   info->IncludeDirectories[info->NumberOfIncludeDirectories++] =
3012     vtkParse_CacheString(info->Strings, name, strlen(name));
3013 }
3014
3015 /**
3016  * Find an include file in the path.  If system_first is set,
3017  * then the current directory is not searched.
3018  */
3019 const char *vtkParsePreprocess_FindIncludeFile(
3020   PreprocessInfo *info, const char *filename, int system_first,
3021   int *already_loaded)
3022 {
3023   const char *cp;
3024   cp = preproc_find_include_file(info, filename, system_first, 1);
3025   if (cp)
3026     {
3027     *already_loaded = 1;
3028     return cp;
3029     }
3030
3031   *already_loaded = 0;
3032   return preproc_find_include_file(info, filename, system_first, 0);
3033 }
3034
3035 /**
3036  * Initialize a preprocessor macro struct
3037  */
3038 void vtkParsePreprocess_InitMacro(MacroInfo *macro)
3039 {
3040   macro->Name = NULL;
3041   macro->Definition = NULL;
3042   macro->Comment = NULL;
3043   macro->NumberOfParameters = 0;
3044   macro->Parameters = NULL;
3045   macro->IsFunction = 0;
3046   macro->IsVariadic = 0;
3047   macro->IsExternal = 0;
3048   macro->IsExcluded = 0;
3049 }
3050
3051 /**
3052  * Free a preprocessor macro struct
3053  */
3054 void vtkParsePreprocess_FreeMacro(MacroInfo *macro)
3055 {
3056   free((char **)macro->Parameters);
3057
3058   free(macro);
3059 }
3060
3061 /**
3062  * Initialize a preprocessor struct
3063  */
3064 void vtkParsePreprocess_Init(
3065   PreprocessInfo *info, const char *filename)
3066 {
3067   info->FileName = NULL;
3068   info->MacroHashTable = NULL;
3069   info->NumberOfIncludeDirectories = 0;
3070   info->IncludeDirectories = NULL;
3071   info->NumberOfIncludeFiles = 0;
3072   info->IncludeFiles = NULL;
3073   info->Strings = NULL;
3074   info->IsExternal = 0;
3075   info->ConditionalDepth = 0;
3076   info->ConditionalDone = 0;
3077
3078   if (filename)
3079     {
3080     char *cp = (char *)malloc(strlen(filename) + 1);
3081     strcpy(cp, filename);
3082     info->FileName = cp;
3083     }
3084 }
3085
3086 /**
3087  * Free a preprocessor struct and its contents
3088  */
3089 void vtkParsePreprocess_Free(PreprocessInfo *info)
3090 {
3091   int i, n;
3092   MacroInfo **mptr;
3093
3094   free((char *)info->FileName);
3095
3096   if (info->MacroHashTable)
3097     {
3098     n = PREPROC_HASH_TABLE_SIZE;
3099     for (i = 0; i < n; i++)
3100       {
3101       mptr = info->MacroHashTable[i];
3102       if (mptr)
3103         {
3104         while (*mptr)
3105           {
3106           vtkParsePreprocess_FreeMacro(*mptr++);
3107           }
3108         }
3109       free(info->MacroHashTable[i]);
3110       }
3111     free(info->MacroHashTable);
3112     }
3113
3114   free((char **)info->IncludeDirectories);
3115   free((char **)info->IncludeFiles);
3116
3117   free(info);
3118 }