1 /*=========================================================================
3 Program: Visualization Toolkit
4 Module: vtkWrapHierarchy.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 -------------------------------------------------------------------------*/
23 The vtkWrapHierarchy program builds a text file that describes the
25 For each class, the output file will have a line in the following
28 classname [ : superclass ] ; header.h ; kit [; flags]
32 enumname : enum ; header.h ; kit [; flags]
36 name = [2][3]* const int ; header.h ; kit [; flags]
41 #include "vtkParseInternal.h"
42 #include "vtkParsePreprocess.h"
54 * Helper to append a text line to an array of lines
56 static char **append_unique_line(char **lines, char *line, size_t *np)
62 /* check to make sure this line isn't a duplicate */
63 for (l = 0; l < n; l++)
65 if (strcmp(line, lines[l]) == 0)
72 /* allocate more memory if n+1 is a power of two */
75 lines = (char **)realloc(lines, (n+1)*2*sizeof(char *));
78 lines[n] = (char *)malloc(strlen(line)+1);
79 strcpy(lines[n++], line);
88 * Helper to append to a line, given the end marker
90 static char *append_to_line(
91 char *line, const char *text, size_t *pos, size_t *maxlen)
97 if ((*pos) + n + 1 > (*maxlen))
99 *maxlen = ((*pos) + n + 1 + 2*(*maxlen));
100 line = (char *)realloc(line, (*maxlen));
103 strcpy(&line[*pos], text);
110 * Append scope to line
112 static char *append_scope_to_line(
113 char *line, size_t *m, size_t *maxlen, const char *scope)
115 if (scope && scope[0] != '\0')
117 line = append_to_line(line, scope, m, maxlen);
118 line = append_to_line(line, "::", m, maxlen);
125 * Append template info
127 static char *append_template_to_line(
128 char *line, size_t *m, size_t *maxlen, TemplateArgs *template_args)
133 line = append_to_line(line, "<", m, maxlen);
135 for (j = 0; j < template_args->NumberOfArguments; j++)
137 arg = template_args->Arguments[j];
138 line = append_to_line(line, arg->Name, m, maxlen);
139 if (arg->Value && arg->Value[0] != '\n')
141 line = append_to_line(line, "=", m, maxlen);
142 line = append_to_line(line, arg->Value, m, maxlen);
144 if (j+1 < template_args->NumberOfArguments)
146 line = append_to_line(line, ",", m, maxlen);
150 line = append_to_line(line, ">", m, maxlen);
158 static char *append_class_to_line(
159 char *line, size_t *m, size_t *maxlen, ClassInfo *class_info)
163 line = append_to_line(line, class_info->Name, m, maxlen);
165 if (class_info->Template)
167 line = append_template_to_line(line, m, maxlen, class_info->Template);
170 line = append_to_line(line, " ", m, maxlen);
172 if (class_info->NumberOfSuperClasses)
174 line = append_to_line(line, ": ", m, maxlen);
177 for (j = 0; j < class_info->NumberOfSuperClasses; j++)
179 line = append_to_line(line, class_info->SuperClasses[j], m, maxlen);
180 line = append_to_line(line, " ", m, maxlen);
181 if (j+1 < class_info->NumberOfSuperClasses)
183 line = append_to_line(line, ", ", m, maxlen);
193 static char *append_enum_to_line(
194 char *line, size_t *m, size_t *maxlen, EnumInfo *enum_info)
196 line = append_to_line(line, enum_info->Name, m, maxlen);
197 line = append_to_line(line, " : enum ", m, maxlen);
203 * Append the trailer, i.e. the filename and flags
205 static char *append_trailer(
206 char *line, size_t *m, size_t *maxlen,
207 const char *header_file, const char *module_name, const char *flags)
209 line = append_to_line(line, "; ", m, maxlen);
210 line = append_to_line(line, header_file, m, maxlen);
212 line = append_to_line(line, " ; ", m, maxlen);
213 line = append_to_line(line, module_name, m, maxlen);
215 if (flags && flags[0] != '\0')
217 line = append_to_line(line, " ; ", m, maxlen);
218 line = append_to_line(line, flags, m, maxlen);
225 * Append typedef info
227 static char *append_typedef_to_line(
228 char *line, size_t *m, size_t *maxlen, ValueInfo *typedef_info)
234 line = append_to_line(line, typedef_info->Name, m, maxlen);
235 line = append_to_line(line, " = ", m, maxlen);
237 type = typedef_info->Type;
239 if ((type & VTK_PARSE_REF) != 0)
241 line = append_to_line(line, "&", m, maxlen);
244 ndims = typedef_info->NumberOfDimensions;
246 for (dim = 0; dim < ndims; dim++)
248 line = append_to_line(line, "[", m, maxlen);
249 line = append_to_line(line, typedef_info->Dimensions[dim],
251 line = append_to_line(line, "]", m, maxlen);
254 type = (type & VTK_PARSE_POINTER_MASK);
255 if (ndims > 0 && (type & VTK_PARSE_POINTER_LOWMASK) == VTK_PARSE_ARRAY)
257 type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
261 type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
264 /* pointers are printed after brackets, and are intentionally
265 * printed in reverse order as compared to C++ declarations */
268 unsigned int bits = (type & VTK_PARSE_POINTER_LOWMASK);
269 type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
271 if (bits == VTK_PARSE_POINTER)
273 line = append_to_line(line, "*", m, maxlen);
275 else if (bits == VTK_PARSE_CONST_POINTER)
277 line = append_to_line(line, "const*", m, maxlen);
281 line = append_to_line(line, "[]", m, maxlen);
285 if (line[*m-1] != ' ')
287 line = append_to_line(line, " ", m, maxlen);
290 if ((type & VTK_PARSE_CONST) != 0)
292 line = append_to_line(line, "const ", m, maxlen);
295 line = append_to_line(line, typedef_info->Class, m, maxlen);
296 line = append_to_line(line, " ", m, maxlen);
302 * Append all types in a class
304 static char **append_class_contents(
305 char **lines, size_t *np, ClassInfo *data,
306 const char *scope, const char *header_file, const char *module_name)
309 const char *tmpflags;
313 size_t scope_m, scope_maxlen;
315 /* append the name to the scope */
325 m = strlen(data->Name);
327 if (m && (n || data->Template))
329 scope_maxlen = n + m + 3;
331 new_scope = (char *)malloc(scope_maxlen);
335 new_scope = append_to_line(new_scope, scope, &scope_m, &scope_maxlen);
336 new_scope = append_to_line(new_scope, "::", &scope_m, &scope_maxlen);
338 new_scope = append_to_line(new_scope, data->Name, &scope_m, &scope_maxlen);
341 new_scope = append_template_to_line(
342 new_scope, &scope_m, &scope_maxlen, data->Template);
351 /* start with a buffer of 15 chars and grow from there */
354 line = (char *)malloc(maxlen);
356 /* add a line for each type that is found */
357 for (i = 0; i < data->NumberOfItems; i++)
364 if (data->Items[i].Type == VTK_CLASS_INFO ||
365 data->Items[i].Type == VTK_STRUCT_INFO)
367 ClassInfo *class_info =
368 data->Classes[data->Items[i].Index];
370 line = append_scope_to_line(line, &m, &maxlen, scope);
371 line = append_class_to_line(line, &m, &maxlen, class_info);
372 tmpflags = "WRAP_EXCLUDE";
374 else if (data->Items[i].Type == VTK_ENUM_INFO)
376 line = append_scope_to_line(line, &m, &maxlen, scope);
377 line = append_enum_to_line(line, &m, &maxlen,
378 data->Enums[data->Items[i].Index]);
380 else if (data->Items[i].Type == VTK_TYPEDEF_INFO)
382 line = append_scope_to_line(line, &m, &maxlen, scope);
383 line = append_typedef_to_line(line, &m, &maxlen,
384 data->Typedefs[data->Items[i].Index]);
388 /* unhandled file element */
392 /* append filename and flags */
393 line = append_trailer(
394 line, &m, &maxlen, header_file, module_name, tmpflags);
396 /* append the line to the file */
397 lines = append_unique_line(lines, line, np);
399 /* for classes, add all typed defined within the class */
400 if ((data->Items[i].Type == VTK_CLASS_INFO ||
401 data->Items[i].Type == VTK_STRUCT_INFO) &&
402 data->Classes[data->Items[i].Index]->Name)
404 lines = append_class_contents(lines, np,
405 data->Classes[data->Items[i].Index],
406 scope, header_file, module_name);
422 * Append all types in a namespace
424 static char **append_namespace_contents(
425 char **lines, size_t *np, NamespaceInfo *data, ClassInfo *main_class,
426 const char *scope, const char *header_file, const char *module_name,
430 const char *tmpflags;
435 /* append the name to the scope */
445 m = strlen(data->Name);
449 new_scope = (char *)malloc(m + n + 3);
452 strncpy(new_scope, scope, n);
453 new_scope[n++] = ':';
454 new_scope[n++] = ':';
456 strncpy(&new_scope[n], data->Name, m);
457 new_scope[n+m] = '\0';
465 /* start with a buffer of 15 chars and grow from there */
468 line = (char *)malloc(maxlen);
470 /* add a line for each type that is found */
471 for (i = 0; i < data->NumberOfItems; i++)
477 if (data->Items[i].Type == VTK_CLASS_INFO ||
478 data->Items[i].Type == VTK_STRUCT_INFO)
480 ClassInfo *class_info =
481 data->Classes[data->Items[i].Index];
483 /* all but the main class in each file is excluded from wrapping */
484 tmpflags = "WRAP_EXCLUDE";
485 if (class_info == main_class)
490 line = append_scope_to_line(line, &m, &maxlen, scope);
491 line = append_class_to_line(line, &m, &maxlen, class_info);
493 else if (data->Items[i].Type == VTK_ENUM_INFO)
495 line = append_scope_to_line(line, &m, &maxlen, scope);
496 line = append_enum_to_line(line, &m, &maxlen,
497 data->Enums[data->Items[i].Index]);
499 else if (data->Items[i].Type == VTK_TYPEDEF_INFO)
501 line = append_scope_to_line(line, &m, &maxlen, scope);
502 line = append_typedef_to_line(line, &m, &maxlen,
503 data->Typedefs[data->Items[i].Index]);
507 /* unhandled file element */
511 /* append filename and flags */
512 line = append_trailer(
513 line, &m, &maxlen, header_file, module_name, tmpflags);
515 /* append the line to the file */
516 lines = append_unique_line(lines, line, np);
518 /* for classes, add all typed defined within the class */
519 if ((data->Items[i].Type == VTK_CLASS_INFO ||
520 data->Items[i].Type == VTK_STRUCT_INFO) &&
521 data->Classes[data->Items[i].Index]->Name)
523 lines = append_class_contents(lines, np,
524 data->Classes[data->Items[i].Index],
525 scope, header_file, module_name);
528 /* for namespaces, add all types in the namespace */
529 if (data->Items[i].Type == VTK_NAMESPACE_INFO &&
530 data->Namespaces[data->Items[i].Index]->Name)
532 lines = append_namespace_contents(lines, np,
533 data->Namespaces[data->Items[i].Index], 0,
534 scope, header_file, module_name, "WRAP_EXCLUDE");
549 * Read a header file with vtkParse.tab.c
551 * If "lines" is provided, the file contents
552 * will be appended to them.
554 static char **vtkWrapHierarchy_ParseHeaderFile(
555 FILE *fp, const char *filename, const char *module_name,
556 const char *flags, char **lines)
559 const char *header_file;
562 /* start with just a single output line and grow from there */
565 lines = (char **)malloc(sizeof(char *));
569 /* always ignore BTX markers when building hierarchy files */
570 vtkParse_SetIgnoreBTX(1);
572 /* the "concrete" flag doesn't matter, just set to zero */
573 data = vtkParse_ParseFile(filename, fp, stderr);
581 /* find the last line in "lines" */
583 while (lines[n] != NULL)
588 k = strlen(data->FileName) - 1;
589 while (k > 0 && data->FileName[k-1] != '/' && data->FileName[k-1] != '\\')
593 header_file = &data->FileName[k];
595 /* append the file contents to the output */
596 lines = append_namespace_contents(
597 lines, &n, data->Contents, data->MainClass, 0,
598 header_file, module_name, flags);
606 * Read a hierarchy file into "lines" without duplicating lines
608 static char **vtkWrapHierarchy_ReadHierarchyFile(FILE *fp, char **lines)
614 line = (char *)malloc(maxlen);
618 lines = (char **)malloc(sizeof(char *));
622 while (fgets(line, (int)maxlen, fp))
626 /* if buffer not long enough, increase it */
627 while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
630 line = (char *)realloc(line, maxlen);
631 if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
632 n += strlen(&line[n]);
635 while (n > 0 && isspace(line[n-1]))
646 for (i = 0; lines[i] != NULL; i++)
648 if (strcmp(line, lines[i]) == 0)
654 if (lines[i] == NULL)
656 /* allocate more memory if n+1 is a power of two */
657 if (((i+1) & i) == 0)
659 lines = (char **)realloc(lines, (i+1)*2*sizeof(char *));
662 lines[i] = (char *)malloc(n+1);
663 strcpy(lines[i], line);
680 * Compare a file to "lines", return 0 if they are different
682 static int vtkWrapHierarchy_CompareHierarchyFile(FILE *fp, char *lines[])
684 unsigned char *matched;
689 line = (char *)malloc(maxlen);
691 for (i = 0; lines[i] != NULL; i++) { ; };
692 matched = (unsigned char *)malloc(i);
693 memset(matched, 0, i);
695 while (fgets(line, (int)maxlen, fp))
699 /* if buffer not long enough, increase it */
700 while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
703 line = (char *)realloc(line, maxlen);
704 if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
705 n += strlen(&line[n]);
708 while (n > 0 && isspace(line[n-1]))
719 for (i = 0; lines[i] != NULL; i++)
721 if (strcmp(line, lines[i]) == 0)
727 if (lines[i] == NULL)
736 for (i = 0; lines[i] != NULL; i++)
757 * Write "lines" to a hierarchy file
759 static int vtkWrapHierarchy_WriteHierarchyFile(FILE *fp, char *lines[])
763 for (i = 0; lines[i] != NULL; i++)
765 if (fprintf(fp, "%s\n", lines[i]) < 0)
775 * Try to parse a header file, print error and exit if fail
777 static char **vtkWrapHierarchy_TryParseHeaderFile(
778 const char *file_name, const char *module_name,
779 const char *flags, char **lines)
783 input_file = fopen(file_name, "r");
787 fprintf(stderr, "vtkWrapHierarchy: couldn't open file %s\n",
792 lines = vtkWrapHierarchy_ParseHeaderFile(
793 input_file, file_name, module_name, flags, lines);
806 * Try to read a file, print error and exit if fail
808 static char **vtkWrapHierarchy_TryReadHierarchyFile(
809 const char *file_name, char **lines)
813 input_file = fopen(file_name, "r");
816 fprintf(stderr, "vtkWrapHierarchy: couldn't open file %s\n",
821 lines = vtkWrapHierarchy_ReadHierarchyFile(input_file, lines);
825 fprintf(stderr, "vtkWrapHierarchy: error reading file %s\n",
835 * Try to write a file, print error and exit if fail
837 static int vtkWrapHierarchy_TryWriteHierarchyFile(
838 const char *file_name, char *lines[])
843 output_file = fopen(file_name, "r");
844 if (output_file && vtkWrapHierarchy_CompareHierarchyFile(output_file, lines))
856 output_file = fopen(file_name, "w");
857 while (!output_file && tries < 5)
859 /* There are two CMAKE_CUSTOM_COMMANDS for vtkWrapHierarchy,
860 * make sure they do not collide. */
867 output_file = fopen(file_name, "r+");
869 vtkWrapHierarchy_CompareHierarchyFile(output_file, lines))
871 /* if the contents match, no need to write it */
877 /* close and open in order to truncate the file */
879 output_file = fopen(file_name, "w");
884 fprintf(stderr, "vtkWrapHierarchy: tried %i times to write %s\n",
888 if (!vtkWrapHierarchy_WriteHierarchyFile(output_file, lines))
891 fprintf(stderr, "vtkWrapHierarchy: error writing file %s\n",
901 static int string_compare(const void *vp1, const void *vp2)
903 return strcmp(*(const char **)vp1, *(const char **)vp2);
906 int main(int argc, char *argv[])
909 char *output_filename = 0;
918 const char *optionargval;
920 /* parse command-line options */
921 for (argi = 1; argi < argc && argv[argi][0] == '-'; argi++)
923 if (strncmp(argv[argi], "-o", 2) == 0 ||
924 strncmp(argv[argi], "-I", 2) == 0 ||
925 strncmp(argv[argi], "-D", 2) == 0 ||
926 strncmp(argv[argi], "-U", 2) == 0)
929 optionarg = &argv[argi][2];
930 if (argv[argi][2] == '\0')
933 if (argi >= argc || argv[argi][0] == '-')
938 optionarg = argv[argi];
940 if (strncmp(option, "-o", 2) == 0)
942 output_filename = optionarg;
944 else if (strncmp(option, "-I", 2) == 0)
946 vtkParse_IncludeDirectory(optionarg);
948 else if (strncmp(option, "-D", 2) == 0)
952 while (optionarg[j] != '\0' && optionarg[j] != '=') { j++; }
953 if (optionarg[j] == '=')
955 optionargval = &optionarg[j+1];
957 vtkParse_DefineMacro(optionarg, optionargval);
959 else if (strncmp(option, "-U", 2) == 0)
961 vtkParse_UndefineMacro(optionarg);
966 if (usage_error || !output_filename || argc - argi < 1)
969 "Usage: %s -o output_file data_file [files_to_merge]\n",
974 /* read the data file */
975 files = vtkWrapHierarchy_TryReadHierarchyFile(argv[argi++], files);
977 /* read in all the prior files */
980 lines = vtkWrapHierarchy_TryReadHierarchyFile(argv[argi++], lines);
983 /* merge the files listed in the data file */
984 for (i = 0; files[i] != NULL; i++)
986 /* look for semicolon that marks the module name */
987 module_name = files[i];
988 while(*module_name != ';' && *module_name != '\0') { module_name++; };
989 if (*module_name == ';') { *module_name++ = '\0'; }
991 /* look for semicolon that marks start of flags */
993 while(*flags != ';' && *flags != '\0') { flags++; };
994 if (*flags == ';') { *flags++ = '\0'; }
996 lines = vtkWrapHierarchy_TryParseHeaderFile(
997 files[i], module_name, flags, lines);
1000 /* sort the lines to ease lookups in the file */
1001 for (n = 0; lines[n]; n++) { ; };
1002 qsort(lines, n, sizeof(char *), &string_compare);
1004 /* write the file, if it has changed */
1005 vtkWrapHierarchy_TryWriteHierarchyFile(output_filename, lines);
1007 for (j = 0; j < n; j++)