Salome HOME
CMake: porting module to the new CMake procedure.
[modules/paravis.git] / src / VTKWrapping / ParaView / vtkParseHierarchy.c
1 /*=========================================================================
2
3   Program:   Visualization Toolkit
4   Module:    vtkParseHierarchy.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 "vtkParseHierarchy.h"
23 #include "vtkParseExtras.h"
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <assert.h>
29
30 static size_t skip_space(const char *text)
31 {
32   size_t i = 0;
33   while (isspace(text[i]) && text[i] != '\n') { i++; }
34   return i;
35 }
36
37 static size_t skip_expression(const char *text, const char *delims)
38 {
39   char newdelims[2];
40   size_t i = 0;
41   size_t j;
42   int use_angle = 0;
43   char c;
44
45   for (j = 0; delims[j] != '\0'; j++)
46     {
47     if (delims[j] == '>')
48       {
49       use_angle = 1;
50       }
51     }
52
53   while (text[i] != '\0')
54     {
55     c = text[i];
56     j = 0;
57     while (c != delims[j] && delims[j] != '\0') { j++; }
58     if (delims[j] != '\0' || c == '\0') { break; }
59     if (c == '\"' || c == '\'')
60       {
61       char d = c;
62       i++;
63       while (text[i] != d && text[i] != '\0')
64         {
65         if (text[i] == '\\' && text[i+1] != '\0') { i++; }
66         i++;
67         }
68       c = text[i];
69       if (c == '\0') { break; }
70       }
71     i++;
72     if (c == '(' || c == '[' || c == '{' || (use_angle && c == '<'))
73       {
74       if (c == '(') { newdelims[0] = ')'; }
75       if (c == '[') { newdelims[0] = ']'; }
76       if (c == '{') { newdelims[0] = '}'; }
77       if (c == '<') { newdelims[0] = '>'; }
78       newdelims[1] = '\0';
79
80       i += skip_expression(&text[i], newdelims);
81
82       if (text[i] == newdelims[0]) { i++; } else { break; }
83       }
84     }
85
86   return i;
87 }
88
89 /* helper: comparison of entries */
90 static int compare_hierarchy_entries(const void *vp1, const void *vp2)
91 {
92   const HierarchyEntry *entry1 = (const HierarchyEntry *)vp1;
93   const HierarchyEntry *entry2 = (const HierarchyEntry *)vp2;
94
95   return strcmp(entry1->Name, entry2->Name);
96 }
97
98 /* helper: sort the entries to facilitate searching */
99 static void sort_hierarchy_entries(HierarchyInfo *info)
100 {
101   qsort(info->Entries, info->NumberOfEntries, sizeof(HierarchyEntry),
102         &compare_hierarchy_entries);
103 }
104
105 /* Find an entry with a binary search */
106 HierarchyEntry *vtkParseHierarchy_FindEntry(
107   const HierarchyInfo *info, const char *classname)
108 {
109   HierarchyEntry key;
110   HierarchyEntry *entry;
111   size_t i, n;
112   char name[32];
113   char *cp;
114
115   /* use classname as-is for the search if possible */
116   cp = (char *)classname;
117
118   /* get portion of name before final template parameters */
119   n = vtkParse_UnscopedNameLength(classname);
120   i = 0;
121   while (classname[i+n] == ':' && classname[i+n+1] == ':')
122     {
123     i += n + 2;
124     n = vtkParse_UnscopedNameLength(&classname[i]);
125     }
126   i += vtkParse_IdentifierLength(&classname[i]);
127
128   /* create a new (shorter) search string if necessary */
129   if (classname[i] != '\0')
130     {
131     /* use stack space if possible */
132     cp = name;
133     /* otherwise, use malloc */
134     if (i > 31)
135       {
136       cp = (char *)malloc(i+1);
137       }
138     strncpy(cp, classname, i);
139     cp[i] = '\0';
140     }
141
142   key.Name = cp;
143
144   entry = (HierarchyEntry *)bsearch(&key, info->Entries,
145     info->NumberOfEntries, sizeof(HierarchyEntry),
146     &compare_hierarchy_entries);
147
148   if (cp != classname && cp != name)
149     {
150     free(cp);
151     }
152
153   return entry;
154 }
155
156
157 /* read a hierarchy file into a HeirarchyInfo struct, or return NULL */
158 HierarchyInfo *vtkParseHierarchy_ReadFile(const char *filename)
159 {
160   HierarchyInfo *info;
161   HierarchyEntry *entry;
162   int maxClasses = 500;
163   FILE *fp;
164   char *line;
165   char *cp;
166   const char *ccp;
167   size_t maxlen = 15;
168   size_t i, j, n, m;
169   unsigned int bits, pointers;
170   static const char *delims = ">,=";
171
172   line = (char *)malloc(maxlen);
173
174   fp = fopen(filename, "r");
175
176   if (fp == NULL)
177     {
178     return NULL;
179     }
180
181   info = (HierarchyInfo *)malloc(sizeof(HierarchyInfo));
182   info->NumberOfEntries = 0;
183   info->Entries = (HierarchyEntry *)malloc(maxClasses*sizeof(HierarchyEntry));
184   info->Strings = (StringCache *)malloc(sizeof(StringCache));
185   vtkParse_InitStringCache(info->Strings);
186
187   while (fgets(line, (int)maxlen, fp))
188     {
189     n = strlen(line);
190
191     /* if buffer not long enough, increase it */
192     while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
193       {
194       maxlen *= 2;
195       line = (char *)realloc(line, maxlen);
196       if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
197       n += strlen(&line[n]);
198       }
199
200     while (n > 0 && isspace(line[n-1]))
201       {
202       n--;
203       }
204     line[n] = '\0';
205
206     if (line[0] == '\0')
207       {
208       continue;
209       }
210
211     if (info->NumberOfEntries == maxClasses)
212       {
213       maxClasses *= 2;
214       info->Entries = (HierarchyEntry *)realloc(
215         info->Entries, sizeof(HierarchyEntry)*maxClasses*2);
216       }
217
218     entry = &info->Entries[info->NumberOfEntries++];
219     entry->Name = NULL;
220     entry->HeaderFile = NULL;
221     entry->Module = NULL;
222     entry->NumberOfTemplateParameters = 0;
223     entry->TemplateParameters = NULL;
224     entry->TemplateDefaults = NULL;
225     entry->NumberOfProperties = 0;
226     entry->Properties = NULL;
227     entry->NumberOfSuperClasses = 0;
228     entry->SuperClasses = NULL;
229     entry->SuperClassIndex = NULL;
230     entry->Typedef = NULL;
231     entry->IsTypedef = 0;
232     entry->IsEnum = 0;
233
234     i = skip_space(line);
235     n = vtkParse_NameLength(&line[i]);
236     for (m = 0; m < n; m++)
237       {
238       if (line[i+m] == '<') { break; }
239       }
240
241     entry->Name = vtkParse_CacheString(info->Strings, &line[i], m);
242     i += m;
243
244     if (line[i] == '<')
245       {
246       i++;
247       i += skip_space(&line[i]);
248
249       for (j = 0; line[i] != '>' && line[i] != '\0'; j++)
250         {
251         if (j == 0)
252           {
253           entry->TemplateParameters = (const char **)malloc(sizeof(char *));
254           entry->TemplateDefaults = (const char **)malloc(sizeof(char *));
255           }
256         else
257           {
258           entry->TemplateParameters = (const char **)realloc(
259             (char **)entry->TemplateParameters, (j+1)*sizeof(char *));
260           entry->TemplateDefaults = (const char **)realloc(
261             (char **)entry->TemplateDefaults, (j+1)*sizeof(char *));
262           }
263         entry->NumberOfTemplateParameters++;
264         entry->TemplateDefaults[j] = NULL;
265
266         m = skip_expression(&line[i], delims);
267         while (m > 0 && (line[i+m-1] == ' ' || line[i+m-1] == '\t'))
268           {
269           --m;
270           }
271
272         entry->TemplateParameters[j] =
273           vtkParse_CacheString(info->Strings, &line[i], m);
274         i += m;
275         i += skip_space(&line[i]);
276
277         if (line[i] == '=')
278           {
279           i++;
280           i += skip_space(&line[i]);
281           m = skip_expression(&line[i], delims);
282           while (m > 0 && (line[i+m-1] == ' ' || line[i+m-1] == '\t'))
283             {
284             --m;
285             }
286           entry->TemplateDefaults[j] =
287             vtkParse_CacheString(info->Strings, &line[i], m);
288           i += m;
289           i += skip_space(&line[i]);
290           }
291
292         if (line[i] == ',')
293           {
294           i++;
295           i += skip_space(&line[i]);
296           }
297         }
298
299       if (line[i] == '>')
300         {
301         i++;
302         i += skip_space(&line[i]);
303         }
304
305       if (line[i] == ':' && line[i+1] == ':')
306         {
307         i += 2;
308         m = vtkParse_NameLength(&line[i]);
309         n = strlen(entry->Name);
310         cp = vtkParse_NewString(info->Strings, n+m+2);
311         strcpy(cp, entry->Name);
312         strcpy(&cp[n], "::");
313         strncpy(&cp[n+2], &line[i], m);
314         i += m;
315         cp[n+m+2] = '\0';
316         entry->Name = cp;
317         }
318       }
319
320     i += skip_space(&line[i]);
321
322     /* classes (and possibly enums) */
323     if (line[i] == ':')
324       {
325       i++;
326       i += skip_space(&line[i]);
327       n = vtkParse_NameLength(&line[i]);
328       /* check for enum indicators */
329       if ((n == 3 && strncmp(&line[i], "int", n)) ||
330           (n == 4 && strncmp(&line[i], "enum", n)))
331         {
332         entry->IsEnum = 1;
333         i += n;
334         i += skip_space(&line[i]);
335         }
336       /* else check for superclasses */
337       else for (j = 0; ; j++)
338         {
339         if (j == 0)
340           {
341           entry->SuperClasses = (const char **)malloc(sizeof(char *));
342           entry->SuperClassIndex = (int *)malloc(sizeof(int));
343           }
344         else
345           {
346           entry->SuperClasses = (const char **)realloc(
347             (char **)entry->SuperClasses, (j+1)*sizeof(char *));
348           entry->SuperClassIndex = (int *)realloc(
349             entry->SuperClassIndex, (j+1)*sizeof(int));
350           }
351         entry->NumberOfSuperClasses++;
352
353         i += skip_space(&line[i]);
354         n = vtkParse_NameLength(&line[i]);
355         entry->SuperClasses[j] =
356           vtkParse_CacheString(info->Strings, &line[i], n);
357         entry->SuperClassIndex[j] = -1;
358         i += n;
359
360         i += skip_space(&line[i]);
361         if (line[i] != ',')
362           {
363           break;
364           }
365         i++;
366         }
367       }
368
369     /* read typedefs */
370     else if (line[i] == '=')
371       {
372       i++;
373       i += skip_space(&line[i]);
374       entry->IsTypedef = 1;
375       entry->Typedef = (ValueInfo *)malloc(sizeof(ValueInfo));
376       vtkParse_InitValue(entry->Typedef);
377
378       /* type is a reference (does this ever occur?) */
379       if (line[i] == '&')
380         {
381         i++;
382         i += skip_space(&line[i]);
383         entry->Typedef->Type |= VTK_PARSE_REF;
384         }
385
386       /* type has array dimensions */
387       if (line[i] == '[')
388         {
389         entry->Typedef->Count = 1;
390         }
391
392       while (line[i] == '[')
393         {
394         i++;
395         n = 0;
396         while (line[i+n] != ']' && line[i+n] != '\n' && line[i+n] != '\0')
397           {
398           n++;
399           }
400         ccp = vtkParse_CacheString(info->Strings, &line[i], n);
401         vtkParse_AddStringToArray(&entry->Typedef->Dimensions,
402                                   &entry->Typedef->NumberOfDimensions, ccp);
403         if (ccp[0] >= '0' && ccp[0] <= '9')
404           {
405           entry->Typedef->Count *= (int)strtol(ccp, NULL, 0);
406           }
407         else
408           {
409           entry->Typedef->Count = 0;
410           }
411         i += n;
412         if (line[i] == ']')
413           {
414           i++;
415           }
416         }
417       i += skip_space(&line[i]);
418
419       /* look for pointers (and const pointers) */
420       bits = 0;
421       while (line[i] == '*' || strncmp(&line[i], "const*", 6) == 0)
422         {
423         bits = (bits << 2);
424         if (line[i] == '*')
425           {
426           bits = (bits | VTK_PARSE_POINTER);
427           }
428         else
429           {
430           bits = (bits | VTK_PARSE_CONST_POINTER);
431           i += 5;
432           }
433         bits = (bits & VTK_PARSE_POINTER_MASK);
434         i++;
435         i += skip_space(&line[i]);
436         }
437
438       /* need to reverse to get correct pointer order */
439       pointers = 0;
440       while (bits)
441         {
442         pointers = (pointers << 2);
443         pointers = (pointers | (bits & VTK_PARSE_POINTER_LOWMASK));
444         bits = ((bits >> 2) & VTK_PARSE_POINTER_MASK);
445         }
446
447       /* add pointer indirection to correspond to first array dimension */
448       if (entry->Typedef->NumberOfDimensions > 1)
449         {
450         pointers = ((pointers << 2) | VTK_PARSE_ARRAY);
451         }
452       else if (entry->Typedef->NumberOfDimensions == 1)
453         {
454         pointers = ((pointers << 2) | VTK_PARSE_POINTER);
455         }
456
457       /* include the pointers in the type */
458       entry->Typedef->Type |= (pointers & VTK_PARSE_POINTER_MASK);
459
460       /* read the base type (and const) */
461       bits = 0;
462       i += vtkParse_BasicTypeFromString(&line[i], &bits, &ccp, &n);
463       entry->Typedef->Class = vtkParse_CacheString(info->Strings, ccp, n);
464       entry->Typedef->Type |= bits;
465       }
466
467     /* get the header file */
468     if (line[i] == ';')
469       {
470       i++;
471       i += skip_space(&line[i]);
472       n = 0;
473       while(line[i+n] != '\0' && line[i+n] != ';' &&
474             !isspace(line[i+n])) { n++; };
475       entry->HeaderFile = vtkParse_CacheString(info->Strings, &line[i], n);
476
477       i += n;
478       i += skip_space(&line[i]);
479
480       /* get the module */
481       if (line[i] == ';')
482         {
483         i++;
484         i += skip_space(&line[i]);
485         n = 0;
486         while(line[i+n] != '\0' && line[i+n] != ';' &&
487               !isspace(line[i+n])) { n++; };
488         entry->Module = vtkParse_CacheString(info->Strings, &line[i], n);
489
490         i += n;
491         i += skip_space(&line[i]);
492         }
493
494       /* get all flags */
495       while (line[i] == ';')
496         {
497         i++;
498         i += skip_space(&line[i]);
499         if (entry->NumberOfProperties == 0)
500           {
501           entry->Properties = (const char **)malloc(sizeof(char **));
502           }
503         else
504           {
505           entry->Properties = (const char **)realloc(
506             (char **)entry->Properties,
507             (entry->NumberOfProperties+1)*sizeof(char **));
508           }
509         n = 0;
510         while (line[i+n] != '\0' && line[i+n] != '\n' && line[i+n] != ';')
511           { n++; }
512         if (n && skip_space(&line[i]) != n)
513           {
514           entry->Properties[entry->NumberOfProperties++] =
515             vtkParse_CacheString(info->Strings, &line[i], n);
516           }
517         i += n;
518         }
519       }
520     }
521
522   if (!feof(fp))
523     {
524     vtkParseHierarchy_Free(info);
525     info = NULL;
526     }
527
528   free(line);
529
530   sort_hierarchy_entries(info);
531
532   return info;
533 }
534
535 /* free a HierarchyInfo struct */
536 void vtkParseHierarchy_Free(HierarchyInfo *info)
537 {
538   HierarchyEntry *entry;
539   int i;
540
541   for (i = 0; i < info->NumberOfEntries; i++)
542     {
543     entry = &info->Entries[i];
544     if (entry->NumberOfTemplateParameters)
545       {
546       free((char **)entry->TemplateParameters);
547       free((char **)entry->TemplateDefaults);
548       }
549     if (entry->NumberOfSuperClasses)
550       {
551       free((char **)entry->SuperClasses);
552       free(entry->SuperClassIndex);
553       }
554     if (entry->NumberOfProperties)
555       {
556       free((char **)entry->Properties);
557       }
558     }
559
560   free(info->Entries);
561   free(info);
562 }
563
564
565 /* Check whether class is derived from baseclass.  You must supply
566  * the entry for the class (returned by FindEntry) as well as the
567  * classname.  If the class is templated, the classname can include
568  * template args in angle brackets.  If you provide a pointer for
569  * baseclass_with_args, then it will be used to return the name of
570  * name of the baseclass with template args in angle brackets. */
571
572 int vtkParseHierarchy_IsTypeOfTemplated(
573   const HierarchyInfo *info,
574   const HierarchyEntry *entry, const char *classname,
575   const char *baseclass, const char **baseclass_with_args)
576 {
577   HierarchyEntry *tmph;
578   const char *name;
579   const char *supername;
580   char *tmp;
581   int templated;
582   int baseclass_is_template_parameter;
583   int supername_needs_free = 0;
584   int classname_needs_free = 0;
585   int i, j, k;
586   int nargs;
587   const char **args;
588   size_t m;
589   int iterating = 1;
590   int rval = 0;
591
592   while (iterating)
593     {
594     iterating = 0;
595     templated = 0;
596     baseclass_is_template_parameter = 0;
597     nargs = 0;
598     args = NULL;
599
600     /* if classname is the same as baseclass, done! */
601     if (strcmp(entry->Name, baseclass) == 0)
602       {
603       if (baseclass_with_args)
604         {
605         if (!classname_needs_free)
606           {
607           tmp = (char *)malloc(strlen(classname) + 1);
608           strcpy(tmp, classname);
609           classname = tmp;
610           }
611         *baseclass_with_args = classname;
612         classname_needs_free = 0;
613         }
614       rval = 1;
615       break;
616       }
617     else if (entry->NumberOfSuperClasses == 0)
618       {
619       rval = 0;
620       break;
621       }
622
623     /* if class is templated */
624     if (entry->NumberOfTemplateParameters)
625       {
626       /* check for template args for classname */
627       m = strlen(entry->Name);
628       if (classname[m] == '<')
629         {
630         templated = 1;
631
632         nargs = entry->NumberOfTemplateParameters;
633         vtkParse_DecomposeTemplatedType(classname, &name, nargs, &args,
634           entry->TemplateDefaults);
635         }
636       }
637
638     /* check all baseclasses */
639     for (j = 0; j < entry->NumberOfSuperClasses && rval == 0; j++)
640       {
641       supername = entry->SuperClasses[j];
642
643       if (templated)
644         {
645         for (k = 0; k < entry->NumberOfTemplateParameters; k++)
646           {
647           /* check if the baseclass itself is a template parameter */
648           m = strlen(entry->TemplateParameters[k]);
649           if (strncmp(entry->TemplateParameters[k], supername, m) == 0 &&
650               !isalnum(supername[m]) && supername[m] != '_')
651             {
652             baseclass_is_template_parameter = 1;
653             break;
654             }
655           }
656
657         /* use the class template args to find baseclass template args */
658         supername = vtkParse_StringReplace(
659           supername, entry->NumberOfTemplateParameters, entry->TemplateParameters, args);
660         if (supername != entry->SuperClasses[j])
661           {
662           supername_needs_free = 1;
663           }
664         }
665
666       /* check the cached index for the baseclass entry */
667       i = entry->SuperClassIndex[j];
668       if (i == -1)
669         {
670         /* index was not set yet, so search for the entry */
671         tmph = vtkParseHierarchy_FindEntry(info, supername);
672         while (tmph && tmph->IsTypedef)
673           {
674           if (tmph->Typedef->Class)
675             {
676             tmph = vtkParseHierarchy_FindEntry(info, tmph->Typedef->Class);
677             continue;
678             }
679           break;
680           }
681
682         if (tmph)
683           {
684           i = (int)(tmph - info->Entries);
685           }
686         else
687           {
688           /* entry not found, don't try again */
689           /* i = -2; messes things up for templates */
690           /* fprintf(stderr, "not found \"%s\"\n", entry->SuperClasses[j]); */
691           }
692
693         /* if baseclass is a template parameter, its entry cannot be cached */
694         if (!baseclass_is_template_parameter)
695           {
696           /* cache the position of the baseclass */
697           ((HierarchyEntry *)entry)->SuperClassIndex[j] = i;
698           }
699         }
700
701       /* if entry was found, continue down the chain */
702       if (i >= 0)
703         {
704         if (classname_needs_free)
705           {
706           free((char *)classname);
707           }
708         classname = supername;
709         classname_needs_free = supername_needs_free;
710         supername_needs_free = 0;
711
712         /* use the iteration loop instead of recursion */
713         if (j+1 >= entry->NumberOfSuperClasses)
714           {
715           entry = &info->Entries[i];
716           iterating = 1;
717           }
718
719         /* recurse for multiple inheritance */
720         else
721           {
722           rval = vtkParseHierarchy_IsTypeOfTemplated(
723                    info, &info->Entries[i], classname, baseclass,
724                    baseclass_with_args);
725           }
726         }
727
728       if (supername_needs_free)
729         {
730         free((char *)supername);
731         supername_needs_free = 0;
732         }
733
734       } /* end of loop over superclasses */
735
736     if (templated)
737       {
738       vtkParse_FreeTemplateDecomposition(name, nargs, args);
739       }
740
741     } /* end of "while (iterating)" */
742
743   if (classname_needs_free)
744     {
745     free((char *)classname);
746     }
747
748   if (baseclass_with_args && !rval)
749     {
750     *baseclass_with_args = NULL;
751     }
752
753   return rval;
754 }
755
756 int vtkParseHierarchy_IsTypeOf(
757   const HierarchyInfo *info, const HierarchyEntry *entry,
758   const char *baseclass)
759 {
760   return vtkParseHierarchy_IsTypeOfTemplated(
761     info, entry, entry->Name, baseclass, NULL);
762 }
763
764 /* Free args returned by IsTypeOfTemplated */
765 void vtkParseHierarchy_FreeTemplateArgs(int n, const char *args[])
766 {
767   int i;
768
769   for (i = 0; i < n; i++)
770     {
771     free((char *)args[i]);
772     }
773
774   free((char **)args);
775 }
776
777 /* Given a classname with template parameters, get the superclass name
778  * with corresponding template parameters.  Returns null if 'i' is out
779  * of range, i.e. greater than or equal to the number of superclasses.
780  * The returned classname must be freed with "free()". */
781 const char *vtkParseHierarchy_TemplatedSuperClass(
782   const HierarchyEntry *entry, const char *classname, int i)
783 {
784   const char *supername = NULL;
785   const char *name;
786   const char **args;
787   char *cp;
788   size_t j;
789
790   if (i < entry->NumberOfSuperClasses)
791     {
792     supername = entry->SuperClasses[i];
793     j = vtkParse_IdentifierLength(classname);
794
795     if (classname[j] == '<')
796       {
797       vtkParse_DecomposeTemplatedType(classname, &name,
798         entry->NumberOfTemplateParameters, &args, entry->TemplateDefaults);
799       supername = vtkParse_StringReplace(entry->SuperClasses[i],
800         entry->NumberOfTemplateParameters, entry->TemplateParameters, args);
801       vtkParse_FreeTemplateDecomposition(
802         name, entry->NumberOfTemplateParameters, args);
803       }
804
805     if (supername == entry->SuperClasses[i])
806       {
807       cp = (char *)malloc(strlen(supername) + 1);
808       strcpy(cp, supername);
809       supername = cp;
810       }
811     }
812
813   return supername;
814 }
815
816 /* get the specified property, or return NULL */
817 const char *vtkParseHierarchy_GetProperty(
818   const HierarchyEntry *entry, const char *property)
819 {
820   int i;
821   size_t k;
822
823   if (entry)
824     {
825     for (i = 0; i < entry->NumberOfProperties; i++)
826       {
827       /* skip the property name, everything after is the property */
828       k = vtkParse_NameLength(entry->Properties[i]);
829       if (k == strlen(property) &&
830           strncmp(entry->Properties[i], property, k) == 0)
831         {
832         if (entry->Properties[i][k] == ' ' ||
833             entry->Properties[i][k] == '=') { k++; }
834         return &entry->Properties[i][k];
835         }
836       }
837     }
838
839   return NULL;
840 }
841
842 /* Expand all unrecognized types in a ValueInfo struct by
843  * using the typedefs in the HierarchyInfo struct. */
844 int vtkParseHierarchy_ExpandTypedefsInValue(
845   const HierarchyInfo *info, ValueInfo *val, StringCache *cache,
846   const char *scope)
847 {
848   char text[128];
849   char *cp;
850   const char *newclass;
851   size_t n, m;
852   int i;
853   HierarchyEntry *entry;
854   int scope_needs_free = 0;
855   int result = 1;
856
857   while (((val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_OBJECT ||
858           (val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_UNKNOWN) &&
859          val->Class != 0)
860     {
861     entry = 0;
862
863     /* search for the type in the provided scope */
864     while (entry == 0 && scope != 0)
865       {
866       cp = text;
867       n = strlen(scope);
868       m = strlen(val->Class);
869       /* only malloc if more than 128 chars needed */
870       if (n + m + 2 >= 128)
871         {
872         cp = (char *)malloc(n+m+3);
873         }
874
875       /* scope the name */
876       strncpy(cp, scope, n);
877       cp[n++] = ':';
878       cp[n++] = ':';
879       strncpy(&cp[n], val->Class, m);
880       cp[n+m] = '\0';
881
882       entry = vtkParseHierarchy_FindEntry(info, cp);
883
884       if (cp != text) { free(cp); }
885
886       /* if not found, try inherited scopes */
887       if (entry == 0)
888         {
889         entry = vtkParseHierarchy_FindEntry(info, scope);
890         scope = 0;
891         scope_needs_free = 0;
892         if (entry && entry->NumberOfSuperClasses)
893           {
894           for (i = 0; i+1 < entry->NumberOfSuperClasses; i++)
895             {
896             if (scope_needs_free) { free((char *)scope); }
897             scope = vtkParseHierarchy_ExpandTypedefsInName(
898               info, entry->SuperClasses[i], NULL);
899             scope_needs_free = (scope != entry->SuperClasses[i]);
900             /* recurse if more than one superclass */
901             if (vtkParseHierarchy_ExpandTypedefsInValue(
902                   info, val, cache, scope))
903               {
904               if (scope_needs_free) { free((char *)scope); }
905               return 1;
906               }
907             }
908           if (scope_needs_free) { free((char *)scope); }
909           scope = vtkParseHierarchy_ExpandTypedefsInName(
910             info, entry->SuperClasses[i], NULL);
911           scope_needs_free = (scope != entry->SuperClasses[i]);
912           }
913         entry = 0;
914         }
915       }
916
917     /* if not found, try again with no scope */
918     if (entry == 0)
919       {
920       entry = vtkParseHierarchy_FindEntry(info, val->Class);
921       }
922
923     if (entry && entry->IsTypedef)
924       {
925       vtkParse_ExpandTypedef(val, entry->Typedef);
926       }
927     else if (entry)
928       {
929       newclass = vtkParseHierarchy_ExpandTypedefsInName(
930          info, val->Class, scope);
931       if (newclass != val->Class)
932         {
933         val->Class = vtkParse_CacheString(cache, newclass, strlen(newclass));
934         free((char *)newclass);
935         }
936       result = 1;
937       break;
938       }
939     else
940       {
941       result = 0;
942       break;
943       }
944     }
945
946   if (scope_needs_free) { free((char *)scope); }
947
948   return result;
949 }
950
951 /* Expand typedefs found in an expression stored as a string.
952  * The value of "text" will be returned if no expansion occurred,
953  * else a new string is returned that must be freed with "free()". */
954 const char *vtkParseHierarchy_ExpandTypedefsInName(
955   const HierarchyInfo *info, const char *name, const char *scope)
956 {
957   char text[128];
958   char *cp;
959   size_t n, m;
960   const char *newname = name;
961   HierarchyEntry *entry = NULL;
962
963   /* note: unlike ExpandTypedefsInValue, this does not yet recurse
964    * or look in superclass scopes */
965
966   /* doesn't yet handle names that are scoped or templated */
967   m = vtkParse_IdentifierLength(name);
968   if (name[m] != '\0')
969     {
970     return name;
971     }
972
973   if (scope)
974     {
975     cp = text;
976     n = strlen(scope);
977     m = strlen(name);
978     /* only malloc if more than 128 chars needed */
979     if (n + m + 2 >= 128)
980       {
981       cp = (char *)malloc(n+m+3);
982       }
983
984     /* scope the name */
985     strncpy(cp, scope, n);
986     cp[n++] = ':';
987     cp[n++] = ':';
988     strncpy(&cp[n], name, m);
989     cp[n+m] = '\0';
990
991     entry = vtkParseHierarchy_FindEntry(info, cp);
992
993     if (cp != text) { free(cp); }
994     }
995
996   if (!entry)
997     {
998     entry = vtkParseHierarchy_FindEntry(info, name);
999     }
1000
1001   newname = NULL;
1002   if (entry && entry->IsTypedef && entry->Typedef->Class)
1003     {
1004     newname = entry->Typedef->Class;
1005     }
1006   if (newname)
1007     {
1008     cp = (char *)malloc(strlen(newname) + 1);
1009     strcpy(cp, newname);
1010     name = cp;
1011     }
1012
1013   return name;
1014 }