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 line = (char *)malloc(maxlen);
174 fp = fopen(filename, "r");
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);
535 /* free a HierarchyInfo struct */
536 void vtkParseHierarchy_Free(HierarchyInfo *info)
538 HierarchyEntry *entry;
541 for (i = 0; i < info->NumberOfEntries; i++)
543 entry = &info->Entries[i];
544 if (entry->NumberOfTemplateParameters)
546 free((char **)entry->TemplateParameters);
547 free((char **)entry->TemplateDefaults);
549 if (entry->NumberOfSuperClasses)
551 free((char **)entry->SuperClasses);
552 free(entry->SuperClassIndex);
554 if (entry->NumberOfProperties)
556 free((char **)entry->Properties);
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. */
572 int vtkParseHierarchy_IsTypeOfTemplated(
573 const HierarchyInfo *info,
574 const HierarchyEntry *entry, const char *classname,
575 const char *baseclass, const char **baseclass_with_args)
577 HierarchyEntry *tmph;
579 const char *supername;
582 int baseclass_is_template_parameter;
583 int supername_needs_free = 0;
584 int classname_needs_free = 0;
596 baseclass_is_template_parameter = 0;
600 /* if classname is the same as baseclass, done! */
601 if (strcmp(entry->Name, baseclass) == 0)
603 if (baseclass_with_args)
605 if (!classname_needs_free)
607 tmp = (char *)malloc(strlen(classname) + 1);
608 strcpy(tmp, classname);
611 *baseclass_with_args = classname;
612 classname_needs_free = 0;
617 else if (entry->NumberOfSuperClasses == 0)
623 /* if class is templated */
624 if (entry->NumberOfTemplateParameters)
626 /* check for template args for classname */
627 m = strlen(entry->Name);
628 if (classname[m] == '<')
632 nargs = entry->NumberOfTemplateParameters;
633 vtkParse_DecomposeTemplatedType(classname, &name, nargs, &args,
634 entry->TemplateDefaults);
638 /* check all baseclasses */
639 for (j = 0; j < entry->NumberOfSuperClasses && rval == 0; j++)
641 supername = entry->SuperClasses[j];
645 for (k = 0; k < entry->NumberOfTemplateParameters; k++)
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] != '_')
652 baseclass_is_template_parameter = 1;
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])
662 supername_needs_free = 1;
666 /* check the cached index for the baseclass entry */
667 i = entry->SuperClassIndex[j];
670 /* index was not set yet, so search for the entry */
671 tmph = vtkParseHierarchy_FindEntry(info, supername);
672 while (tmph && tmph->IsTypedef)
674 if (tmph->Typedef->Class)
676 tmph = vtkParseHierarchy_FindEntry(info, tmph->Typedef->Class);
684 i = (int)(tmph - info->Entries);
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]); */
693 /* if baseclass is a template parameter, its entry cannot be cached */
694 if (!baseclass_is_template_parameter)
696 /* cache the position of the baseclass */
697 ((HierarchyEntry *)entry)->SuperClassIndex[j] = i;
701 /* if entry was found, continue down the chain */
704 if (classname_needs_free)
706 free((char *)classname);
708 classname = supername;
709 classname_needs_free = supername_needs_free;
710 supername_needs_free = 0;
712 /* use the iteration loop instead of recursion */
713 if (j+1 >= entry->NumberOfSuperClasses)
715 entry = &info->Entries[i];
719 /* recurse for multiple inheritance */
722 rval = vtkParseHierarchy_IsTypeOfTemplated(
723 info, &info->Entries[i], classname, baseclass,
724 baseclass_with_args);
728 if (supername_needs_free)
730 free((char *)supername);
731 supername_needs_free = 0;
734 } /* end of loop over superclasses */
738 vtkParse_FreeTemplateDecomposition(name, nargs, args);
741 } /* end of "while (iterating)" */
743 if (classname_needs_free)
745 free((char *)classname);
748 if (baseclass_with_args && !rval)
750 *baseclass_with_args = NULL;
756 int vtkParseHierarchy_IsTypeOf(
757 const HierarchyInfo *info, const HierarchyEntry *entry,
758 const char *baseclass)
760 return vtkParseHierarchy_IsTypeOfTemplated(
761 info, entry, entry->Name, baseclass, NULL);
764 /* Free args returned by IsTypeOfTemplated */
765 void vtkParseHierarchy_FreeTemplateArgs(int n, const char *args[])
769 for (i = 0; i < n; i++)
771 free((char *)args[i]);
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)
784 const char *supername = NULL;
790 if (i < entry->NumberOfSuperClasses)
792 supername = entry->SuperClasses[i];
793 j = vtkParse_IdentifierLength(classname);
795 if (classname[j] == '<')
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);
805 if (supername == entry->SuperClasses[i])
807 cp = (char *)malloc(strlen(supername) + 1);
808 strcpy(cp, supername);
816 /* get the specified property, or return NULL */
817 const char *vtkParseHierarchy_GetProperty(
818 const HierarchyEntry *entry, const char *property)
825 for (i = 0; i < entry->NumberOfProperties; i++)
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)
832 if (entry->Properties[i][k] == ' ' ||
833 entry->Properties[i][k] == '=') { k++; }
834 return &entry->Properties[i][k];
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,
850 const char *newclass;
853 HierarchyEntry *entry;
854 int scope_needs_free = 0;
857 while (((val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_OBJECT ||
858 (val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_UNKNOWN) &&
863 /* search for the type in the provided scope */
864 while (entry == 0 && scope != 0)
868 m = strlen(val->Class);
869 /* only malloc if more than 128 chars needed */
870 if (n + m + 2 >= 128)
872 cp = (char *)malloc(n+m+3);
876 strncpy(cp, scope, n);
879 strncpy(&cp[n], val->Class, m);
882 entry = vtkParseHierarchy_FindEntry(info, cp);
884 if (cp != text) { free(cp); }
886 /* if not found, try inherited scopes */
889 entry = vtkParseHierarchy_FindEntry(info, scope);
891 scope_needs_free = 0;
892 if (entry && entry->NumberOfSuperClasses)
894 for (i = 0; i+1 < entry->NumberOfSuperClasses; i++)
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))
904 if (scope_needs_free) { free((char *)scope); }
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]);
917 /* if not found, try again with no scope */
920 entry = vtkParseHierarchy_FindEntry(info, val->Class);
923 if (entry && entry->IsTypedef)
925 vtkParse_ExpandTypedef(val, entry->Typedef);
929 newclass = vtkParseHierarchy_ExpandTypedefsInName(
930 info, val->Class, scope);
931 if (newclass != val->Class)
933 val->Class = vtkParse_CacheString(cache, newclass, strlen(newclass));
934 free((char *)newclass);
946 if (scope_needs_free) { free((char *)scope); }
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)
960 const char *newname = name;
961 HierarchyEntry *entry = NULL;
963 /* note: unlike ExpandTypedefsInValue, this does not yet recurse
964 * or look in superclass scopes */
966 /* doesn't yet handle names that are scoped or templated */
967 m = vtkParse_IdentifierLength(name);
978 /* only malloc if more than 128 chars needed */
979 if (n + m + 2 >= 128)
981 cp = (char *)malloc(n+m+3);
985 strncpy(cp, scope, n);
988 strncpy(&cp[n], name, m);
991 entry = vtkParseHierarchy_FindEntry(info, cp);
993 if (cp != text) { free(cp); }
998 entry = vtkParseHierarchy_FindEntry(info, name);
1002 if (entry && entry->IsTypedef && entry->Typedef->Class)
1004 newname = entry->Typedef->Class;
1008 cp = (char *)malloc(strlen(newname) + 1);
1009 strcpy(cp, newname);