1 /*=========================================================================
3 Program: Visualization Toolkit
4 Module: vtkParseHierarchy.c
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
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.
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16 Copyright (c) 2010 David Gobbi.
18 Contributed to the VisualizationToolkit by the author in June 2010
19 under the terms of the Visualization Toolkit 2008 copyright.
20 -------------------------------------------------------------------------*/
22 #include "vtkParseHierarchy.h"
23 #include "vtkParseExtras.h"
30 static size_t skip_space(const char *text)
33 while (isspace(text[i]) && text[i] != '\n') { i++; }
37 static size_t skip_expression(const char *text, const char *delims)
45 for (j = 0; delims[j] != '\0'; j++)
53 while (text[i] != '\0')
57 while (c != delims[j] && delims[j] != '\0') { j++; }
58 if (delims[j] != '\0' || c == '\0') { break; }
59 if (c == '\"' || c == '\'')
63 while (text[i] != d && text[i] != '\0')
65 if (text[i] == '\\' && text[i+1] != '\0') { i++; }
69 if (c == '\0') { break; }
72 if (c == '(' || c == '[' || c == '{' || (use_angle && c == '<'))
74 if (c == '(') { newdelims[0] = ')'; }
75 if (c == '[') { newdelims[0] = ']'; }
76 if (c == '{') { newdelims[0] = '}'; }
77 if (c == '<') { newdelims[0] = '>'; }
80 i += skip_expression(&text[i], newdelims);
82 if (text[i] == newdelims[0]) { i++; } else { break; }
89 /* helper: comparison of entries */
90 static int compare_hierarchy_entries(const void *vp1, const void *vp2)
92 const HierarchyEntry *entry1 = (const HierarchyEntry *)vp1;
93 const HierarchyEntry *entry2 = (const HierarchyEntry *)vp2;
95 return strcmp(entry1->Name, entry2->Name);
98 /* helper: sort the entries to facilitate searching */
99 static void sort_hierarchy_entries(HierarchyInfo *info)
101 qsort(info->Entries, info->NumberOfEntries, sizeof(HierarchyEntry),
102 &compare_hierarchy_entries);
105 /* Find an entry with a binary search */
106 HierarchyEntry *vtkParseHierarchy_FindEntry(
107 const HierarchyInfo *info, const char *classname)
110 HierarchyEntry *entry;
115 /* use classname as-is for the search if possible */
116 cp = (char *)classname;
118 /* get portion of name before final template parameters */
119 n = vtkParse_UnscopedNameLength(classname);
121 while (classname[i+n] == ':' && classname[i+n+1] == ':')
124 n = vtkParse_UnscopedNameLength(&classname[i]);
126 i += vtkParse_IdentifierLength(&classname[i]);
128 /* create a new (shorter) search string if necessary */
129 if (classname[i] != '\0')
131 /* use stack space if possible */
133 /* otherwise, use malloc */
136 cp = (char *)malloc(i+1);
138 strncpy(cp, classname, i);
144 entry = (HierarchyEntry *)bsearch(&key, info->Entries,
145 info->NumberOfEntries, sizeof(HierarchyEntry),
146 &compare_hierarchy_entries);
148 if (cp != classname && cp != name)
157 /* read a hierarchy file into a HeirarchyInfo struct, or return NULL */
158 HierarchyInfo *vtkParseHierarchy_ReadFile(const char *filename)
161 HierarchyEntry *entry;
162 int maxClasses = 500;
169 unsigned int bits, pointers;
170 static const char *delims = ">,=";
172 fp = fopen(filename, "r");
179 line = (char *)malloc(maxlen);
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);
187 while (fgets(line, (int)maxlen, fp))
191 /* if buffer not long enough, increase it */
192 while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
195 line = (char *)realloc(line, maxlen);
196 if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
197 n += strlen(&line[n]);
200 while (n > 0 && isspace(line[n-1]))
211 if (info->NumberOfEntries == maxClasses)
214 info->Entries = (HierarchyEntry *)realloc(
215 info->Entries, sizeof(HierarchyEntry)*maxClasses*2);
218 entry = &info->Entries[info->NumberOfEntries++];
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;
234 i = skip_space(line);
235 n = vtkParse_NameLength(&line[i]);
236 for (m = 0; m < n; m++)
238 if (line[i+m] == '<') { break; }
241 entry->Name = vtkParse_CacheString(info->Strings, &line[i], m);
247 i += skip_space(&line[i]);
249 for (j = 0; line[i] != '>' && line[i] != '\0'; j++)
253 entry->TemplateParameters = (const char **)malloc(sizeof(char *));
254 entry->TemplateDefaults = (const char **)malloc(sizeof(char *));
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 *));
263 entry->NumberOfTemplateParameters++;
264 entry->TemplateDefaults[j] = NULL;
266 m = skip_expression(&line[i], delims);
267 while (m > 0 && (line[i+m-1] == ' ' || line[i+m-1] == '\t'))
272 entry->TemplateParameters[j] =
273 vtkParse_CacheString(info->Strings, &line[i], m);
275 i += skip_space(&line[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'))
286 entry->TemplateDefaults[j] =
287 vtkParse_CacheString(info->Strings, &line[i], m);
289 i += skip_space(&line[i]);
295 i += skip_space(&line[i]);
302 i += skip_space(&line[i]);
305 if (line[i] == ':' && line[i+1] == ':')
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);
320 i += skip_space(&line[i]);
322 /* classes (and possibly enums) */
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)))
334 i += skip_space(&line[i]);
336 /* else check for superclasses */
337 else for (j = 0; ; j++)
341 entry->SuperClasses = (const char **)malloc(sizeof(char *));
342 entry->SuperClassIndex = (int *)malloc(sizeof(int));
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));
351 entry->NumberOfSuperClasses++;
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;
360 i += skip_space(&line[i]);
370 else if (line[i] == '=')
373 i += skip_space(&line[i]);
374 entry->IsTypedef = 1;
375 entry->Typedef = (ValueInfo *)malloc(sizeof(ValueInfo));
376 vtkParse_InitValue(entry->Typedef);
378 /* type is a reference (does this ever occur?) */
382 i += skip_space(&line[i]);
383 entry->Typedef->Type |= VTK_PARSE_REF;
386 /* type has array dimensions */
389 entry->Typedef->Count = 1;
392 while (line[i] == '[')
396 while (line[i+n] != ']' && line[i+n] != '\n' && line[i+n] != '\0')
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')
405 entry->Typedef->Count *= (int)strtol(ccp, NULL, 0);
409 entry->Typedef->Count = 0;
417 i += skip_space(&line[i]);
419 /* look for pointers (and const pointers) */
421 while (line[i] == '*' || strncmp(&line[i], "const*", 6) == 0)
426 bits = (bits | VTK_PARSE_POINTER);
430 bits = (bits | VTK_PARSE_CONST_POINTER);
433 bits = (bits & VTK_PARSE_POINTER_MASK);
435 i += skip_space(&line[i]);
438 /* need to reverse to get correct pointer order */
442 pointers = (pointers << 2);
443 pointers = (pointers | (bits & VTK_PARSE_POINTER_LOWMASK));
444 bits = ((bits >> 2) & VTK_PARSE_POINTER_MASK);
447 /* add pointer indirection to correspond to first array dimension */
448 if (entry->Typedef->NumberOfDimensions > 1)
450 pointers = ((pointers << 2) | VTK_PARSE_ARRAY);
452 else if (entry->Typedef->NumberOfDimensions == 1)
454 pointers = ((pointers << 2) | VTK_PARSE_POINTER);
457 /* include the pointers in the type */
458 entry->Typedef->Type |= (pointers & VTK_PARSE_POINTER_MASK);
460 /* read the base type (and const) */
462 i += vtkParse_BasicTypeFromString(&line[i], &bits, &ccp, &n);
463 entry->Typedef->Class = vtkParse_CacheString(info->Strings, ccp, n);
464 entry->Typedef->Type |= bits;
467 /* get the header file */
471 i += skip_space(&line[i]);
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);
478 i += skip_space(&line[i]);
484 i += skip_space(&line[i]);
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);
491 i += skip_space(&line[i]);
495 while (line[i] == ';')
498 i += skip_space(&line[i]);
499 if (entry->NumberOfProperties == 0)
501 entry->Properties = (const char **)malloc(sizeof(char **));
505 entry->Properties = (const char **)realloc(
506 (char **)entry->Properties,
507 (entry->NumberOfProperties+1)*sizeof(char **));
510 while (line[i+n] != '\0' && line[i+n] != '\n' && line[i+n] != ';')
512 if (n && skip_space(&line[i]) != n)
514 entry->Properties[entry->NumberOfProperties++] =
515 vtkParse_CacheString(info->Strings, &line[i], n);
524 vtkParseHierarchy_Free(info);
530 sort_hierarchy_entries(info);
537 /* free a HierarchyInfo struct */
538 void vtkParseHierarchy_Free(HierarchyInfo *info)
540 HierarchyEntry *entry;
543 for (i = 0; i < info->NumberOfEntries; i++)
545 entry = &info->Entries[i];
546 if (entry->NumberOfTemplateParameters)
548 free((char **)entry->TemplateParameters);
549 free((char **)entry->TemplateDefaults);
551 if (entry->NumberOfSuperClasses)
553 free((char **)entry->SuperClasses);
554 free(entry->SuperClassIndex);
556 if (entry->NumberOfProperties)
558 free((char **)entry->Properties);
567 /* Check whether class is derived from baseclass. You must supply
568 * the entry for the class (returned by FindEntry) as well as the
569 * classname. If the class is templated, the classname can include
570 * template args in angle brackets. If you provide a pointer for
571 * baseclass_with_args, then it will be used to return the name of
572 * name of the baseclass with template args in angle brackets. */
574 int vtkParseHierarchy_IsTypeOfTemplated(
575 const HierarchyInfo *info,
576 const HierarchyEntry *entry, const char *classname,
577 const char *baseclass, const char **baseclass_with_args)
579 HierarchyEntry *tmph;
580 const char *name = NULL;
581 const char *supername;
584 int baseclass_is_template_parameter;
585 int supername_needs_free = 0;
586 int classname_needs_free = 0;
598 baseclass_is_template_parameter = 0;
602 /* if classname is the same as baseclass, done! */
603 if (strcmp(entry->Name, baseclass) == 0)
605 if (baseclass_with_args)
607 if (!classname_needs_free)
609 tmp = (char *)malloc(strlen(classname) + 1);
610 strcpy(tmp, classname);
613 *baseclass_with_args = classname;
614 classname_needs_free = 0;
619 else if (entry->NumberOfSuperClasses == 0)
625 /* if class is templated */
626 if (entry->NumberOfTemplateParameters)
628 /* check for template args for classname */
629 m = strlen(entry->Name);
630 if (classname[m] == '<')
634 nargs = entry->NumberOfTemplateParameters;
635 vtkParse_DecomposeTemplatedType(classname, &name, nargs, &args,
636 entry->TemplateDefaults);
640 /* check all baseclasses */
641 for (j = 0; j < entry->NumberOfSuperClasses && rval == 0; j++)
643 supername = entry->SuperClasses[j];
647 for (k = 0; k < entry->NumberOfTemplateParameters; k++)
649 /* check if the baseclass itself is a template parameter */
650 m = strlen(entry->TemplateParameters[k]);
651 if (strncmp(entry->TemplateParameters[k], supername, m) == 0 &&
652 !isalnum(supername[m]) && supername[m] != '_')
654 baseclass_is_template_parameter = 1;
659 /* use the class template args to find baseclass template args */
660 supername = vtkParse_StringReplace(
661 supername, entry->NumberOfTemplateParameters, entry->TemplateParameters, args);
662 if (supername != entry->SuperClasses[j])
664 supername_needs_free = 1;
668 /* check the cached index for the baseclass entry */
669 i = entry->SuperClassIndex[j];
672 /* index was not set yet, so search for the entry */
673 tmph = vtkParseHierarchy_FindEntry(info, supername);
674 while (tmph && tmph->IsTypedef)
676 if (tmph->Typedef->Class)
678 tmph = vtkParseHierarchy_FindEntry(info, tmph->Typedef->Class);
686 i = (int)(tmph - info->Entries);
690 /* entry not found, don't try again */
691 /* i = -2; messes things up for templates */
692 /* fprintf(stderr, "not found \"%s\"\n", entry->SuperClasses[j]); */
695 /* if baseclass is a template parameter, its entry cannot be cached */
696 if (!baseclass_is_template_parameter)
698 /* cache the position of the baseclass */
699 ((HierarchyEntry *)entry)->SuperClassIndex[j] = i;
703 /* if entry was found, continue down the chain */
706 if (classname_needs_free)
708 free((char *)classname);
710 classname = supername;
711 classname_needs_free = supername_needs_free;
712 supername_needs_free = 0;
714 /* use the iteration loop instead of recursion */
715 if (j+1 >= entry->NumberOfSuperClasses)
717 entry = &info->Entries[i];
721 /* recurse for multiple inheritance */
724 rval = vtkParseHierarchy_IsTypeOfTemplated(
725 info, &info->Entries[i], classname, baseclass,
726 baseclass_with_args);
730 if (supername_needs_free)
732 free((char *)supername);
733 supername_needs_free = 0;
736 } /* end of loop over superclasses */
740 vtkParse_FreeTemplateDecomposition(name, nargs, args);
743 } /* end of "while (iterating)" */
745 if (classname_needs_free)
747 free((char *)classname);
750 if (baseclass_with_args && !rval)
752 *baseclass_with_args = NULL;
758 int vtkParseHierarchy_IsTypeOf(
759 const HierarchyInfo *info, const HierarchyEntry *entry,
760 const char *baseclass)
762 return vtkParseHierarchy_IsTypeOfTemplated(
763 info, entry, entry->Name, baseclass, NULL);
766 /* Free args returned by IsTypeOfTemplated */
767 void vtkParseHierarchy_FreeTemplateArgs(int n, const char *args[])
771 for (i = 0; i < n; i++)
773 free((char *)args[i]);
779 /* Given a classname with template parameters, get the superclass name
780 * with corresponding template parameters. Returns null if 'i' is out
781 * of range, i.e. greater than or equal to the number of superclasses.
782 * The returned classname must be freed with "free()". */
783 const char *vtkParseHierarchy_TemplatedSuperClass(
784 const HierarchyEntry *entry, const char *classname, int i)
786 const char *supername = NULL;
792 if (i < entry->NumberOfSuperClasses)
794 supername = entry->SuperClasses[i];
795 j = vtkParse_IdentifierLength(classname);
797 if (classname[j] == '<')
799 vtkParse_DecomposeTemplatedType(classname, &name,
800 entry->NumberOfTemplateParameters, &args, entry->TemplateDefaults);
801 supername = vtkParse_StringReplace(entry->SuperClasses[i],
802 entry->NumberOfTemplateParameters, entry->TemplateParameters, args);
803 vtkParse_FreeTemplateDecomposition(
804 name, entry->NumberOfTemplateParameters, args);
807 if (supername == entry->SuperClasses[i])
809 cp = (char *)malloc(strlen(supername) + 1);
810 strcpy(cp, supername);
818 /* get the specified property, or return NULL */
819 const char *vtkParseHierarchy_GetProperty(
820 const HierarchyEntry *entry, const char *property)
827 for (i = 0; i < entry->NumberOfProperties; i++)
829 /* skip the property name, everything after is the property */
830 k = vtkParse_NameLength(entry->Properties[i]);
831 if (k == strlen(property) &&
832 strncmp(entry->Properties[i], property, k) == 0)
834 if (entry->Properties[i][k] == ' ' ||
835 entry->Properties[i][k] == '=') { k++; }
836 return &entry->Properties[i][k];
844 /* Expand all unrecognized types in a ValueInfo struct by
845 * using the typedefs in the HierarchyInfo struct. */
846 int vtkParseHierarchy_ExpandTypedefsInValue(
847 const HierarchyInfo *info, ValueInfo *val, StringCache *cache,
852 const char *newclass;
855 HierarchyEntry *entry;
856 int scope_needs_free = 0;
859 while (((val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_OBJECT ||
860 (val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_UNKNOWN) &&
865 /* search for the type in the provided scope */
866 while (entry == 0 && scope != 0)
870 m = strlen(val->Class);
871 /* only malloc if more than 128 chars needed */
872 if (n + m + 2 >= 128)
874 cp = (char *)malloc(n+m+3);
878 strncpy(cp, scope, n);
881 strncpy(&cp[n], val->Class, m);
884 entry = vtkParseHierarchy_FindEntry(info, cp);
886 if (cp != text) { free(cp); }
888 /* if not found, try inherited scopes */
891 entry = vtkParseHierarchy_FindEntry(info, scope);
893 scope_needs_free = 0;
894 if (entry && entry->NumberOfSuperClasses)
896 for (i = 0; i+1 < entry->NumberOfSuperClasses; i++)
898 if (scope_needs_free) { free((char *)scope); }
899 scope = vtkParseHierarchy_ExpandTypedefsInName(
900 info, entry->SuperClasses[i], NULL);
901 scope_needs_free = (scope != entry->SuperClasses[i]);
902 /* recurse if more than one superclass */
903 if (vtkParseHierarchy_ExpandTypedefsInValue(
904 info, val, cache, scope))
906 if (scope_needs_free) { free((char *)scope); }
910 if (scope_needs_free) { free((char *)scope); }
911 scope = vtkParseHierarchy_ExpandTypedefsInName(
912 info, entry->SuperClasses[i], NULL);
913 scope_needs_free = (scope != entry->SuperClasses[i]);
919 /* if not found, try again with no scope */
922 entry = vtkParseHierarchy_FindEntry(info, val->Class);
925 if (entry && entry->IsTypedef)
927 vtkParse_ExpandTypedef(val, entry->Typedef);
931 newclass = vtkParseHierarchy_ExpandTypedefsInName(
932 info, val->Class, scope);
933 if (newclass != val->Class)
935 val->Class = vtkParse_CacheString(cache, newclass, strlen(newclass));
936 free((char *)newclass);
948 if (scope_needs_free) { free((char *)scope); }
953 /* Expand typedefs found in an expression stored as a string.
954 * The value of "text" will be returned if no expansion occurred,
955 * else a new string is returned that must be freed with "free()". */
956 const char *vtkParseHierarchy_ExpandTypedefsInName(
957 const HierarchyInfo *info, const char *name, const char *scope)
962 const char *newname = name;
963 HierarchyEntry *entry = NULL;
965 /* note: unlike ExpandTypedefsInValue, this does not yet recurse
966 * or look in superclass scopes */
968 /* doesn't yet handle names that are scoped or templated */
969 m = vtkParse_IdentifierLength(name);
980 /* only malloc if more than 128 chars needed */
981 if (n + m + 2 >= 128)
983 cp = (char *)malloc(n+m+3);
987 strncpy(cp, scope, n);
990 strncpy(&cp[n], name, m);
993 entry = vtkParseHierarchy_FindEntry(info, cp);
995 if (cp != text) { free(cp); }
1000 entry = vtkParseHierarchy_FindEntry(info, name);
1004 if (entry && entry->IsTypedef && entry->Typedef->Class)
1006 newname = entry->Typedef->Class;
1010 cp = (char *)malloc(strlen(newname) + 1);
1011 strcpy(cp, newname);