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 "vtkParseInternal.h"
24 #include "vtkParseExtras.h"
32 static size_t skip_space(const char *text)
35 while (isspace(text[i]) && text[i] != '\n') { i++; }
39 /* helper: comparison of entries */
40 static int compare_hierarchy_entries(const void *vp1, const void *vp2)
42 const HierarchyEntry *entry1 = (const HierarchyEntry *)vp1;
43 const HierarchyEntry *entry2 = (const HierarchyEntry *)vp2;
45 return strcmp(entry1->Name, entry2->Name);
48 /* helper: sort the entries to facilitate searching */
49 static void sort_hierarchy_entries(HierarchyInfo *info)
51 qsort(info->Entries, info->NumberOfEntries, sizeof(HierarchyEntry),
52 &compare_hierarchy_entries);
55 /* Find an entry with a binary search */
56 HierarchyEntry *vtkParseHierarchy_FindEntry(
57 const HierarchyInfo *info, const char *classname)
60 HierarchyEntry *entry;
65 /* use classname as-is for the search if possible */
66 cp = (char *)classname;
68 /* get portion of name before final template parameters */
69 n = vtkParse_UnscopedNameLength(classname);
71 while (classname[i+n] == ':' && classname[i+n+1] == ':')
74 n = vtkParse_UnscopedNameLength(&classname[i]);
76 i += vtkParse_IdentifierLength(&classname[i]);
78 /* create a new (shorter) search string if necessary */
79 if (classname[i] != '\0')
81 /* use stack space if possible */
83 /* otherwise, use malloc */
86 cp = (char *)malloc(i+1);
88 strncpy(cp, classname, i);
94 entry = (HierarchyEntry *)bsearch(&key, info->Entries,
95 info->NumberOfEntries, sizeof(HierarchyEntry),
96 &compare_hierarchy_entries);
98 if (cp != classname && cp != name)
107 /* read a hierarchy file into a HeirarchyInfo struct, or return NULL */
108 HierarchyInfo *vtkParseHierarchy_ReadFile(const char *filename)
111 HierarchyEntry *entry;
112 int maxClasses = 500;
119 unsigned int bits, pointers;
121 line = (char *)malloc(maxlen);
123 fp = fopen(filename, "r");
130 info = (HierarchyInfo *)malloc(sizeof(HierarchyInfo));
131 info->NumberOfEntries = 0;
132 info->Entries = (HierarchyEntry *)malloc(maxClasses*sizeof(HierarchyEntry));
134 while (fgets(line, (int)maxlen, fp))
138 /* if buffer not long enough, increase it */
139 while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
142 line = (char *)realloc(line, maxlen);
143 if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
144 n += strlen(&line[n]);
147 while (n > 0 && isspace(line[n-1]))
158 if (info->NumberOfEntries == maxClasses)
161 info->Entries = (HierarchyEntry *)realloc(
162 info->Entries, sizeof(HierarchyEntry)*maxClasses*2);
165 entry = &info->Entries[info->NumberOfEntries++];
167 entry->HeaderFile = NULL;
168 entry->Module = NULL;
169 entry->NumberOfTemplateArgs = 0;
170 entry->TemplateArgs = NULL;
171 entry->TemplateArgDefaults = NULL;
172 entry->NumberOfProperties = 0;
173 entry->Properties = NULL;
174 entry->NumberOfSuperClasses = 0;
175 entry->SuperClasses = NULL;
176 entry->SuperClassIndex = NULL;
177 entry->Typedef = NULL;
178 entry->IsTypedef = 0;
181 i = skip_space(line);
182 n = vtkParse_NameLength(&line[i]);
183 for (m = 0; m < n; m++)
185 if (line[i+m] == '<') { break; }
188 cp = (char *)malloc(m+1);
189 strncpy(cp, &line[i], m);
197 i += skip_space(&line[i]);
199 for (j = 0; line[i] != '>' && line[i] != '\0'; j++)
203 entry->TemplateArgs = (const char **)malloc(sizeof(char *));
204 entry->TemplateArgDefaults = (const char **)malloc(sizeof(char *));
208 entry->TemplateArgs = (const char **)realloc(
209 (char **)entry->TemplateArgs, (j+1)*sizeof(char *));
210 entry->TemplateArgDefaults = (const char **)realloc(
211 (char **)entry->TemplateArgDefaults, (j+1)*sizeof(char *));
213 entry->NumberOfTemplateArgs++;
214 entry->TemplateArgDefaults[j] = NULL;
216 m = vtkParse_NameLength(&line[i]);
218 cp = (char *)malloc(m+1);
219 strncpy(cp, &line[i], m);
221 entry->TemplateArgs[j] = cp;
223 i += skip_space(&line[i]);
228 i += skip_space(&line[i]);
229 m = vtkParse_NameLength(&line[i]);
231 cp = (char *)malloc(m+1);
232 strncpy(cp, &line[i], m);
234 entry->TemplateArgDefaults[j] = cp;
236 i += skip_space(&line[i]);
242 i += skip_space(&line[i]);
249 i += skip_space(&line[i]);
252 if (line[i] == ':' && line[i+1] == ':')
255 m = vtkParse_NameLength(&line[i]);
256 n = strlen(entry->Name);
257 cp = (char *)malloc(n+m+3);
258 strcpy(cp, entry->Name);
259 strcpy(&cp[n], "::");
260 strncpy(&cp[n+2], &line[i], m);
263 free((char *)entry->Name);
268 i += skip_space(&line[i]);
270 /* classes (and possibly enums) */
274 i += skip_space(&line[i]);
275 n = vtkParse_NameLength(&line[i]);
276 /* check for enum indicators */
277 if ((n == 3 && strncmp(&line[i], "int", n)) ||
278 (n == 4 && strncmp(&line[i], "enum", n)))
282 i += skip_space(&line[i]);
284 /* else check for superclasses */
285 else for (j = 0; ; j++)
289 entry->SuperClasses = (const char **)malloc(sizeof(char *));
290 entry->SuperClassIndex = (int *)malloc(sizeof(int));
294 entry->SuperClasses = (const char **)realloc(
295 (char **)entry->SuperClasses, (j+1)*sizeof(char *));
296 entry->SuperClassIndex = (int *)realloc(
297 entry->SuperClassIndex, (j+1)*sizeof(int));
299 entry->NumberOfSuperClasses++;
301 i += skip_space(&line[i]);
302 n = vtkParse_NameLength(&line[i]);
303 cp = (char *)malloc(n+1);
304 strncpy(cp, &line[i], n);
306 entry->SuperClasses[j] = cp;
307 entry->SuperClassIndex[j] = -1;
310 i += skip_space(&line[i]);
320 else if (line[i] == '=')
323 i += skip_space(&line[i]);
324 entry->IsTypedef = 1;
325 entry->Typedef = (ValueInfo *)malloc(sizeof(ValueInfo));
326 vtkParse_InitValue(entry->Typedef);
328 /* type is a reference (does this ever occur?) */
332 i += skip_space(&line[i]);
333 entry->Typedef->Type |= VTK_PARSE_REF;
336 /* type has array dimensions */
339 entry->Typedef->Count = 1;
342 while (line[i] == '[')
346 while (line[i+n] != ']' && line[i+n] != '\n' && line[i+n] != '\0')
350 ccp = vtkParse_DuplicateString(&line[i], n);
351 vtkParse_AddStringToArray(&entry->Typedef->Dimensions,
352 &entry->Typedef->NumberOfDimensions, ccp);
353 if (ccp[0] >= '0' && ccp[0] <= '9')
355 entry->Typedef->Count *= (int)strtol(ccp, NULL, 0);
359 entry->Typedef->Count = 0;
367 i += skip_space(&line[i]);
369 /* look for pointers (and const pointers) */
371 while (line[i] == '*' || strncmp(&line[i], "const*", 6) == 0)
376 bits = (bits | VTK_PARSE_POINTER);
380 bits = (bits | VTK_PARSE_CONST_POINTER);
383 bits = (bits & VTK_PARSE_POINTER_MASK);
385 i += skip_space(&line[i]);
388 /* need to reverse to get correct pointer order */
392 pointers = (pointers << 2);
393 pointers = (pointers | (bits & VTK_PARSE_POINTER_LOWMASK));
394 bits = ((bits >> 2) & VTK_PARSE_POINTER_MASK);
397 /* add pointer indirection to correspond to first array dimension */
398 if (entry->Typedef->NumberOfDimensions > 1)
400 pointers = ((pointers << 2) | VTK_PARSE_ARRAY);
402 else if (entry->Typedef->NumberOfDimensions == 1)
404 pointers = ((pointers << 2) | VTK_PARSE_POINTER);
407 /* include the pointers in the type */
408 entry->Typedef->Type |= (pointers & VTK_PARSE_POINTER_MASK);
410 /* read the base type (and const) */
412 i += vtkParse_BasicTypeFromString(&line[i], &bits, &ccp, &n);
413 entry->Typedef->Class = vtkParse_DuplicateString(ccp, n);
414 entry->Typedef->Type |= bits;
417 /* get the header file */
421 i += skip_space(&line[i]);
423 while(line[i+n] != '\0' && line[i+n] != ';' &&
424 !isspace(line[i+n])) { n++; };
425 cp = (char *)malloc(n+1);
426 strncpy(cp, &line[i], n);
428 entry->HeaderFile = cp;
431 i += skip_space(&line[i]);
437 i += skip_space(&line[i]);
439 while(line[i+n] != '\0' && line[i+n] != ';' &&
440 !isspace(line[i+n])) { n++; };
441 cp = (char *)malloc(n+1);
442 strncpy(cp, &line[i], n);
447 i += skip_space(&line[i]);
451 while (line[i] == ';')
454 i += skip_space(&line[i]);
455 if (entry->NumberOfProperties == 0)
457 entry->Properties = (const char **)malloc(sizeof(char **));
461 entry->Properties = (const char **)realloc(
462 (char **)entry->Properties,
463 (entry->NumberOfProperties+1)*sizeof(char **));
466 while (line[i+n] != '\0' && line[i+n] != '\n' && line[i+n] != ';')
468 if (n && skip_space(&line[i]) != n)
470 cp = (char *)malloc((n+1)*sizeof(char *));
471 strncpy(cp, &line[i], n);
473 entry->Properties[entry->NumberOfProperties++] = cp;
482 vtkParseHierarchy_Free(info);
488 sort_hierarchy_entries(info);
493 /* free a HierarchyInfo struct */
494 void vtkParseHierarchy_Free(HierarchyInfo *info)
496 HierarchyEntry *entry;
499 for (i = 0; i < info->NumberOfEntries; i++)
501 entry = &info->Entries[i];
502 free((char *)entry->Name);
503 free((char *)entry->HeaderFile);
504 for (j = 0; j < entry->NumberOfTemplateArgs; j++)
506 free((char *)entry->TemplateArgs[j]);
507 if (entry->TemplateArgDefaults[j])
509 free((char *)entry->TemplateArgDefaults[j]);
512 if (entry->NumberOfTemplateArgs)
514 free((char **)entry->TemplateArgs);
515 free((char **)entry->TemplateArgDefaults);
517 for (j = 0; j < entry->NumberOfSuperClasses; j++)
519 free((char *)entry->SuperClasses[j]);
521 if (entry->NumberOfSuperClasses)
523 free((char **)entry->SuperClasses);
524 free(entry->SuperClassIndex);
526 for (j = 0; j < entry->NumberOfProperties; j++)
528 free((char *)entry->Properties[j]);
530 if (entry->NumberOfProperties)
532 free((char **)entry->Properties);
541 /* Check whether class is derived from baseclass. You must supply
542 * the entry for the class (returned by FindEntry) as well as the
543 * classname. If the class is templated, the classname can include
544 * template args in angle brackets. If you provide a pointer for
545 * baseclass_with_args, then it will be used to return the name of
546 * name of the baseclass with template args in angle brackets. */
548 int vtkParseHierarchy_IsTypeOfTemplated(
549 const HierarchyInfo *info,
550 const HierarchyEntry *entry, const char *classname,
551 const char *baseclass, const char **baseclass_with_args)
553 HierarchyEntry *tmph;
555 const char *supername;
558 int baseclass_is_template_parameter;
559 int supername_needs_free = 0;
560 int classname_needs_free = 0;
572 baseclass_is_template_parameter = 0;
576 /* if classname is the same as baseclass, done! */
577 if (strcmp(entry->Name, baseclass) == 0)
579 if (baseclass_with_args)
581 if (!classname_needs_free)
583 tmp = (char *)malloc(strlen(classname) + 1);
584 strcpy(tmp, classname);
587 *baseclass_with_args = classname;
588 classname_needs_free = 0;
593 else if (entry->NumberOfSuperClasses == 0)
599 /* if class is templated */
600 if (entry->NumberOfTemplateArgs)
602 /* check for template args for classname */
603 m = strlen(entry->Name);
604 if (classname[m] == '<')
608 nargs = entry->NumberOfTemplateArgs;
609 vtkParse_DecomposeTemplatedType(classname, &name, nargs, &args,
610 entry->TemplateArgDefaults);
614 /* check all baseclasses */
615 for (j = 0; j < entry->NumberOfSuperClasses && rval == 0; j++)
617 supername = entry->SuperClasses[j];
621 for (k = 0; k < entry->NumberOfTemplateArgs; k++)
623 /* check if the baseclass itself is a template parameter */
624 m = strlen(entry->TemplateArgs[k]);
625 if (strncmp(entry->TemplateArgs[k], supername, m) == 0 &&
626 !isalnum(supername[m]) && supername[m] != '_')
628 baseclass_is_template_parameter = 1;
633 /* use the class template args to find baseclass template args */
634 supername = vtkParse_StringReplace(
635 supername, entry->NumberOfTemplateArgs, entry->TemplateArgs, args);
636 if (supername != entry->SuperClasses[j])
638 supername_needs_free = 1;
642 /* check the cached index for the baseclass entry */
643 i = entry->SuperClassIndex[j];
646 /* index was not set yet, so search for the entry */
647 tmph = vtkParseHierarchy_FindEntry(info, supername);
648 while (tmph && tmph->IsTypedef)
650 if (tmph->Typedef->Class)
652 tmph = vtkParseHierarchy_FindEntry(info, tmph->Typedef->Class);
660 i = (int)(tmph - info->Entries);
664 /* entry not found, don't try again */
665 /* i = -2; messes things up for templates */
666 /* fprintf(stderr, "not found \"%s\"\n", entry->SuperClasses[j]); */
669 /* if baseclass is a template parameter, its entry cannot be cached */
670 if (!baseclass_is_template_parameter)
672 /* cache the position of the baseclass */
673 ((HierarchyEntry *)entry)->SuperClassIndex[j] = i;
677 /* if entry was found, continue down the chain */
680 if (classname_needs_free)
682 free((char *)classname);
684 classname = supername;
685 classname_needs_free = supername_needs_free;
686 supername_needs_free = 0;
688 /* use the iteration loop instead of recursion */
689 if (j+1 >= entry->NumberOfSuperClasses)
691 entry = &info->Entries[i];
695 /* recurse for multiple inheritance */
698 rval = vtkParseHierarchy_IsTypeOfTemplated(
699 info, &info->Entries[i], classname, baseclass,
700 baseclass_with_args);
704 if (supername_needs_free)
706 free((char *)supername);
707 supername_needs_free = 0;
710 } /* end of loop over superclasses */
714 vtkParse_FreeTemplateDecomposition(name, nargs, args);
717 } /* end of "while (iterating)" */
719 if (classname_needs_free)
721 free((char *)classname);
724 if (baseclass_with_args && !rval)
726 *baseclass_with_args = NULL;
732 int vtkParseHierarchy_IsTypeOf(
733 const HierarchyInfo *info, const HierarchyEntry *entry,
734 const char *baseclass)
736 return vtkParseHierarchy_IsTypeOfTemplated(
737 info, entry, entry->Name, baseclass, NULL);
740 /* Free args returned by IsTypeOfTemplated */
741 void vtkParseHierarchy_FreeTemplateArgs(int n, const char *args[])
745 for (i = 0; i < n; i++)
747 free((char *)args[i]);
753 /* Given a classname with template parameters, get the superclass name
754 * with corresponding template parameters. Returns null if 'i' is out
755 * of range, i.e. greater than or equal to the number of superclasses.
756 * The returned classname must be freed with "free()". */
757 const char *vtkParseHierarchy_TemplatedSuperClass(
758 const HierarchyEntry *entry, const char *classname, int i)
760 const char *supername = NULL;
766 if (i < entry->NumberOfSuperClasses)
768 supername = entry->SuperClasses[i];
769 j = vtkParse_IdentifierLength(classname);
771 if (classname[j] == '<')
773 vtkParse_DecomposeTemplatedType(classname, &name,
774 entry->NumberOfTemplateArgs, &args, entry->TemplateArgDefaults);
775 supername = vtkParse_StringReplace(entry->SuperClasses[i],
776 entry->NumberOfTemplateArgs, entry->TemplateArgs, args);
777 vtkParse_FreeTemplateDecomposition(
778 name, entry->NumberOfTemplateArgs, args);
781 if (supername == entry->SuperClasses[i])
783 cp = (char *)malloc(strlen(supername) + 1);
784 strcpy(cp, supername);
792 /* get the specified property, or return NULL */
793 const char *vtkParseHierarchy_GetProperty(
794 const HierarchyEntry *entry, const char *property)
801 for (i = 0; i < entry->NumberOfProperties; i++)
803 /* skip the property name, everything after is the property */
804 k = vtkParse_NameLength(entry->Properties[i]);
805 if (k == strlen(property) &&
806 strncmp(entry->Properties[i], property, k) == 0)
808 if (entry->Properties[i][k] == ' ' ||
809 entry->Properties[i][k] == '=') { k++; }
810 return &entry->Properties[i][k];
818 /* Expand all unrecognized types in a ValueInfo struct by
819 * using the typedefs in the HierarchyInfo struct. */
820 int vtkParseHierarchy_ExpandTypedefsInValue(
821 const HierarchyInfo *info, ValueInfo *val, const char *scope)
825 const char *newclass;
828 HierarchyEntry *entry;
829 int scope_needs_free = 0;
832 while (((val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_OBJECT ||
833 (val->Type & VTK_PARSE_BASE_TYPE) == VTK_PARSE_UNKNOWN) &&
838 /* search for the type in the provided scope */
839 while (entry == 0 && scope != 0)
843 m = strlen(val->Class);
844 /* only malloc if more than 128 chars needed */
845 if (n + m + 2 >= 128)
847 cp = (char *)malloc(n+m+3);
851 strncpy(cp, scope, n);
854 strncpy(&cp[n], val->Class, m);
857 entry = vtkParseHierarchy_FindEntry(info, cp);
859 if (cp != text) { free(cp); }
861 /* if not found, try inherited scopes */
864 entry = vtkParseHierarchy_FindEntry(info, scope);
866 scope_needs_free = 0;
867 if (entry && entry->NumberOfSuperClasses)
869 for (i = 0; i+1 < entry->NumberOfSuperClasses; i++)
871 if (scope_needs_free) { free((char *)scope); }
872 scope = vtkParseHierarchy_ExpandTypedefsInName(
873 info, entry->SuperClasses[i], NULL);
874 scope_needs_free = (scope != entry->SuperClasses[i]);
875 /* recurse if more than one superclass */
876 if (vtkParseHierarchy_ExpandTypedefsInValue(info, val, scope))
878 if (scope_needs_free) { free((char *)scope); }
882 if (scope_needs_free) { free((char *)scope); }
883 scope = vtkParseHierarchy_ExpandTypedefsInName(
884 info, entry->SuperClasses[i], NULL);
885 scope_needs_free = (scope != entry->SuperClasses[i]);
891 /* if not found, try again with no scope */
894 entry = vtkParseHierarchy_FindEntry(info, val->Class);
897 if (entry && entry->IsTypedef)
899 vtkParse_ExpandTypedef(val, entry->Typedef);
903 newclass = vtkParseHierarchy_ExpandTypedefsInName(
904 info, val->Class, scope);
905 if (newclass != val->Class)
907 val->Class = vtkParse_DuplicateString(newclass, strlen(newclass));
908 free((char *)newclass);
920 if (scope_needs_free) { free((char *)scope); }
925 /* Expand typedefs found in an expression stored as a string.
926 * The value of "text" will be returned if no expansion occurred,
927 * else a new string is returned that must be freed with "free()". */
928 const char *vtkParseHierarchy_ExpandTypedefsInName(
929 const HierarchyInfo *info, const char *name, const char *scope)
934 const char *newname = name;
935 HierarchyEntry *entry = NULL;
937 /* note: unlike ExpandTypedefsInValue, this does not yet recurse
938 * or look in superclass scopes */
940 /* doesn't yet handle names that are scoped or templated */
941 m = vtkParse_IdentifierLength(name);
952 /* only malloc if more than 128 chars needed */
953 if (n + m + 2 >= 128)
955 cp = (char *)malloc(n+m+3);
959 strncpy(cp, scope, n);
962 strncpy(&cp[n], name, m);
965 entry = vtkParseHierarchy_FindEntry(info, cp);
967 if (cp != text) { free(cp); }
972 entry = vtkParseHierarchy_FindEntry(info, name);
976 if (entry && entry->IsTypedef && entry->Typedef->Class)
978 newname = entry->Typedef->Class;
982 cp = (char *)malloc(strlen(newname) + 1);