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 "vtkParseData.h"
42 #include "vtkParseMain.h"
43 #include "vtkParsePreprocess.h"
55 * Helper to append a text line to an array of lines
57 static char **append_unique_line(char **lines, char *line, size_t *np)
63 /* check to make sure this line isn't a duplicate */
64 for (l = 0; l < n; l++)
66 if (strcmp(line, lines[l]) == 0)
73 /* allocate more memory if n+1 is a power of two */
76 lines = (char **)realloc(lines, (n+1)*2*sizeof(char *));
79 lines[n] = (char *)malloc(strlen(line)+1);
80 strcpy(lines[n++], line);
89 * Helper to append to a line, given the end marker
91 static char *append_to_line(
92 char *line, const char *text, size_t *pos, size_t *maxlen)
98 if ((*pos) + n + 1 > (*maxlen))
100 *maxlen = ((*pos) + n + 1 + 2*(*maxlen));
101 line = (char *)realloc(line, (*maxlen));
104 strcpy(&line[*pos], text);
111 * Append scope to line
113 static char *append_scope_to_line(
114 char *line, size_t *m, size_t *maxlen, const char *scope)
116 if (scope && scope[0] != '\0')
118 line = append_to_line(line, scope, m, maxlen);
119 line = append_to_line(line, "::", m, maxlen);
126 * Append template info
128 static char *append_template_to_line(
129 char *line, size_t *m, size_t *maxlen, TemplateInfo *template_args)
134 line = append_to_line(line, "<", m, maxlen);
136 for (j = 0; j < template_args->NumberOfParameters; j++)
138 arg = template_args->Parameters[j];
141 line = append_to_line(line, arg->Name, m, maxlen);
143 if (arg->Value && arg->Value[0] != '\n')
145 line = append_to_line(line, "=", m, maxlen);
146 line = append_to_line(line, arg->Value, m, maxlen);
148 if (j+1 < template_args->NumberOfParameters)
150 line = append_to_line(line, ",", m, maxlen);
154 line = append_to_line(line, ">", m, maxlen);
162 static char *append_class_to_line(
163 char *line, size_t *m, size_t *maxlen, ClassInfo *class_info)
167 line = append_to_line(line, class_info->Name, m, maxlen);
169 if (class_info->Template)
171 line = append_template_to_line(line, m, maxlen, class_info->Template);
174 line = append_to_line(line, " ", m, maxlen);
176 if (class_info->NumberOfSuperClasses)
178 line = append_to_line(line, ": ", m, maxlen);
181 for (j = 0; j < class_info->NumberOfSuperClasses; j++)
183 line = append_to_line(line, class_info->SuperClasses[j], m, maxlen);
184 line = append_to_line(line, " ", m, maxlen);
185 if (j+1 < class_info->NumberOfSuperClasses)
187 line = append_to_line(line, ", ", m, maxlen);
197 static char *append_enum_to_line(
198 char *line, size_t *m, size_t *maxlen, EnumInfo *enum_info)
200 line = append_to_line(line, enum_info->Name, m, maxlen);
201 line = append_to_line(line, " : enum ", m, maxlen);
207 * Append the trailer, i.e. the filename and flags
209 static char *append_trailer(
210 char *line, size_t *m, size_t *maxlen,
211 const char *header_file, const char *module_name, const char *flags)
213 line = append_to_line(line, "; ", m, maxlen);
214 line = append_to_line(line, header_file, m, maxlen);
216 line = append_to_line(line, " ; ", m, maxlen);
217 line = append_to_line(line, module_name, m, maxlen);
219 if (flags && flags[0] != '\0')
221 line = append_to_line(line, " ; ", m, maxlen);
222 line = append_to_line(line, flags, m, maxlen);
229 * Append typedef info
231 static char *append_typedef_to_line(
232 char *line, size_t *m, size_t *maxlen, ValueInfo *typedef_info)
238 line = append_to_line(line, typedef_info->Name, m, maxlen);
239 line = append_to_line(line, " = ", m, maxlen);
241 type = typedef_info->Type;
243 if ((type & VTK_PARSE_REF) != 0)
245 line = append_to_line(line, "&", m, maxlen);
248 ndims = typedef_info->NumberOfDimensions;
250 for (dim = 0; dim < ndims; dim++)
252 line = append_to_line(line, "[", m, maxlen);
253 line = append_to_line(line, typedef_info->Dimensions[dim],
255 line = append_to_line(line, "]", m, maxlen);
258 type = (type & VTK_PARSE_POINTER_MASK);
259 if (ndims > 0 && (type & VTK_PARSE_POINTER_LOWMASK) == VTK_PARSE_ARRAY)
261 type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
265 type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
268 /* pointers are printed after brackets, and are intentionally
269 * printed in reverse order as compared to C++ declarations */
272 unsigned int bits = (type & VTK_PARSE_POINTER_LOWMASK);
273 type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
275 if (bits == VTK_PARSE_POINTER)
277 line = append_to_line(line, "*", m, maxlen);
279 else if (bits == VTK_PARSE_CONST_POINTER)
281 line = append_to_line(line, "const*", m, maxlen);
285 line = append_to_line(line, "[]", m, maxlen);
289 if (line[*m-1] != ' ')
291 line = append_to_line(line, " ", m, maxlen);
294 if ((type & VTK_PARSE_CONST) != 0)
296 line = append_to_line(line, "const ", m, maxlen);
299 line = append_to_line(line, typedef_info->Class, m, maxlen);
300 line = append_to_line(line, " ", m, maxlen);
306 * Append all types in a class
308 static char **append_class_contents(
309 char **lines, size_t *np, ClassInfo *data,
310 const char *scope, const char *header_file, const char *module_name)
313 const char *tmpflags;
317 size_t scope_m, scope_maxlen;
319 /* append the name to the scope */
329 m = strlen(data->Name);
331 if (m && (n || data->Template))
333 scope_maxlen = n + m + 3;
335 new_scope = (char *)malloc(scope_maxlen);
339 new_scope = append_to_line(new_scope, scope, &scope_m, &scope_maxlen);
340 new_scope = append_to_line(new_scope, "::", &scope_m, &scope_maxlen);
342 new_scope = append_to_line(new_scope, data->Name, &scope_m, &scope_maxlen);
345 new_scope = append_template_to_line(
346 new_scope, &scope_m, &scope_maxlen, data->Template);
355 /* start with a buffer of 15 chars and grow from there */
358 line = (char *)malloc(maxlen);
360 /* add a line for each type that is found */
361 for (i = 0; i < data->NumberOfItems; i++)
368 if (data->Items[i].Type == VTK_CLASS_INFO ||
369 data->Items[i].Type == VTK_STRUCT_INFO)
371 ClassInfo *class_info =
372 data->Classes[data->Items[i].Index];
374 line = append_scope_to_line(line, &m, &maxlen, scope);
375 line = append_class_to_line(line, &m, &maxlen, class_info);
376 tmpflags = "WRAP_EXCLUDE";
378 else if (data->Items[i].Type == VTK_ENUM_INFO)
380 line = append_scope_to_line(line, &m, &maxlen, scope);
381 line = append_enum_to_line(line, &m, &maxlen,
382 data->Enums[data->Items[i].Index]);
384 else if (data->Items[i].Type == VTK_TYPEDEF_INFO)
386 line = append_scope_to_line(line, &m, &maxlen, scope);
387 line = append_typedef_to_line(line, &m, &maxlen,
388 data->Typedefs[data->Items[i].Index]);
392 /* unhandled file element */
396 /* append filename and flags */
397 line = append_trailer(
398 line, &m, &maxlen, header_file, module_name, tmpflags);
400 /* append the line to the file */
401 lines = append_unique_line(lines, line, np);
403 /* for classes, add all typed defined within the class */
404 if ((data->Items[i].Type == VTK_CLASS_INFO ||
405 data->Items[i].Type == VTK_STRUCT_INFO) &&
406 data->Classes[data->Items[i].Index]->Name)
408 lines = append_class_contents(lines, np,
409 data->Classes[data->Items[i].Index],
410 scope, header_file, module_name);
426 * Append all types in a namespace
428 static char **append_namespace_contents(
429 char **lines, size_t *np, NamespaceInfo *data, ClassInfo *main_class,
430 const char *scope, const char *header_file, const char *module_name,
434 const char *tmpflags;
439 /* append the name to the scope */
449 m = strlen(data->Name);
453 new_scope = (char *)malloc(m + n + 3);
456 strncpy(new_scope, scope, n);
457 new_scope[n++] = ':';
458 new_scope[n++] = ':';
460 strncpy(&new_scope[n], data->Name, m);
461 new_scope[n+m] = '\0';
469 /* start with a buffer of 15 chars and grow from there */
472 line = (char *)malloc(maxlen);
474 /* add a line for each type that is found */
475 for (i = 0; i < data->NumberOfItems; i++)
481 if (data->Items[i].Type == VTK_CLASS_INFO ||
482 data->Items[i].Type == VTK_STRUCT_INFO)
484 ClassInfo *class_info =
485 data->Classes[data->Items[i].Index];
487 /* all but the main class in each file is excluded from wrapping */
488 tmpflags = "WRAP_EXCLUDE";
489 if (class_info == main_class)
494 line = append_scope_to_line(line, &m, &maxlen, scope);
495 line = append_class_to_line(line, &m, &maxlen, class_info);
497 else if (data->Items[i].Type == VTK_ENUM_INFO)
499 line = append_scope_to_line(line, &m, &maxlen, scope);
500 line = append_enum_to_line(line, &m, &maxlen,
501 data->Enums[data->Items[i].Index]);
503 else if (data->Items[i].Type == VTK_TYPEDEF_INFO)
505 line = append_scope_to_line(line, &m, &maxlen, scope);
506 line = append_typedef_to_line(line, &m, &maxlen,
507 data->Typedefs[data->Items[i].Index]);
509 else if (data->Items[i].Type != VTK_NAMESPACE_INFO)
511 /* unhandled file element */
515 if (data->Items[i].Type != VTK_NAMESPACE_INFO)
517 /* append filename and flags */
518 line = append_trailer(
519 line, &m, &maxlen, header_file, module_name, tmpflags);
521 /* append the line to the file */
522 lines = append_unique_line(lines, line, np);
525 /* for classes, add all typed defined within the class */
526 if ((data->Items[i].Type == VTK_CLASS_INFO ||
527 data->Items[i].Type == VTK_STRUCT_INFO) &&
528 data->Classes[data->Items[i].Index]->Name)
530 lines = append_class_contents(lines, np,
531 data->Classes[data->Items[i].Index],
532 scope, header_file, module_name);
535 /* for namespaces, add all types in the namespace */
536 if (data->Items[i].Type == VTK_NAMESPACE_INFO &&
537 data->Namespaces[data->Items[i].Index]->Name)
539 lines = append_namespace_contents(lines, np,
540 data->Namespaces[data->Items[i].Index], 0,
541 scope, header_file, module_name, "WRAP_EXCLUDE");
556 * Read a header file with vtkParse.tab.c
558 * If "lines" is provided, the file contents
559 * will be appended to them.
561 static char **vtkWrapHierarchy_ParseHeaderFile(
562 FILE *fp, const char *filename, const char *module_name,
563 const char *flags, char **lines)
566 const char *header_file;
569 /* start with just a single output line and grow from there */
572 lines = (char **)malloc(sizeof(char *));
576 /* always ignore BTX markers when building hierarchy files */
577 vtkParse_SetIgnoreBTX(1);
579 /* the "concrete" flag doesn't matter, just set to zero */
580 data = vtkParse_ParseFile(filename, fp, stderr);
588 /* find the last line in "lines" */
590 while (lines[n] != NULL)
595 k = strlen(data->FileName) - 1;
596 while (k > 0 && data->FileName[k-1] != '/' && data->FileName[k-1] != '\\')
600 header_file = &data->FileName[k];
602 /* append the file contents to the output */
603 lines = append_namespace_contents(
604 lines, &n, data->Contents, data->MainClass, 0,
605 header_file, module_name, flags);
613 * Read a hierarchy file into "lines" without duplicating lines
615 static char **vtkWrapHierarchy_ReadHierarchyFile(FILE *fp, char **lines)
621 line = (char *)malloc(maxlen);
625 lines = (char **)malloc(sizeof(char *));
629 while (fgets(line, (int)maxlen, fp))
633 /* if buffer not long enough, increase it */
634 while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
637 line = (char *)realloc(line, maxlen);
638 if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
639 n += strlen(&line[n]);
642 while (n > 0 && isspace(line[n-1]))
653 for (i = 0; lines[i] != NULL; i++)
655 if (strcmp(line, lines[i]) == 0)
661 if (lines[i] == NULL)
663 /* allocate more memory if n+1 is a power of two */
664 if (((i+1) & i) == 0)
666 lines = (char **)realloc(lines, (i+1)*2*sizeof(char *));
669 lines[i] = (char *)malloc(n+1);
670 strcpy(lines[i], line);
687 * Compare a file to "lines", return 0 if they are different
689 static int vtkWrapHierarchy_CompareHierarchyFile(FILE *fp, char *lines[])
691 unsigned char *matched;
696 line = (char *)malloc(maxlen);
698 for (i = 0; lines[i] != NULL; i++) { ; };
699 matched = (unsigned char *)malloc(i);
700 memset(matched, 0, i);
702 while (fgets(line, (int)maxlen, fp))
706 /* if buffer not long enough, increase it */
707 while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
710 line = (char *)realloc(line, maxlen);
711 if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
712 n += strlen(&line[n]);
715 while (n > 0 && isspace(line[n-1]))
726 for (i = 0; lines[i] != NULL; i++)
728 if (strcmp(line, lines[i]) == 0)
734 if (lines[i] == NULL)
743 for (i = 0; lines[i] != NULL; i++)
764 * Write "lines" to a hierarchy file
766 static int vtkWrapHierarchy_WriteHierarchyFile(FILE *fp, char *lines[])
770 for (i = 0; lines[i] != NULL; i++)
772 if (fprintf(fp, "%s\n", lines[i]) < 0)
782 * Try to parse a header file, print error and exit if fail
784 static char **vtkWrapHierarchy_TryParseHeaderFile(
785 const char *file_name, const char *module_name,
786 const char *flags, char **lines)
790 input_file = fopen(file_name, "r");
794 fprintf(stderr, "vtkWrapHierarchy: couldn't open file %s\n",
799 lines = vtkWrapHierarchy_ParseHeaderFile(
800 input_file, file_name, module_name, flags, lines);
813 * Try to read a file, print error and exit if fail
815 static char **vtkWrapHierarchy_TryReadHierarchyFile(
816 const char *file_name, char **lines)
820 input_file = fopen(file_name, "r");
823 fprintf(stderr, "vtkWrapHierarchy: couldn't open file %s\n",
828 lines = vtkWrapHierarchy_ReadHierarchyFile(input_file, lines);
832 fprintf(stderr, "vtkWrapHierarchy: error reading file %s\n",
842 * Try to write a file, print error and exit if fail
844 static int vtkWrapHierarchy_TryWriteHierarchyFile(
845 const char *file_name, char *lines[])
850 output_file = fopen(file_name, "r");
851 if (output_file && vtkWrapHierarchy_CompareHierarchyFile(output_file, lines))
863 output_file = fopen(file_name, "w");
864 while (!output_file && tries < 5)
866 /* There are two CMAKE_CUSTOM_COMMANDS for vtkWrapHierarchy,
867 * make sure they do not collide. */
874 output_file = fopen(file_name, "r+");
876 vtkWrapHierarchy_CompareHierarchyFile(output_file, lines))
878 /* if the contents match, no need to write it */
884 /* close and open in order to truncate the file */
886 output_file = fopen(file_name, "w");
891 fprintf(stderr, "vtkWrapHierarchy: tried %i times to write %s\n",
895 if (!vtkWrapHierarchy_WriteHierarchyFile(output_file, lines))
898 fprintf(stderr, "vtkWrapHierarchy: error writing file %s\n",
908 static int string_compare(const void *vp1, const void *vp2)
910 return strcmp(*(const char **)vp1, *(const char **)vp2);
913 int main(int argc, char *argv[])
923 /* parse command-line options */
924 vtkParse_MainMulti(argc, argv);
925 options = vtkParse_GetCommandLineOptions();
927 /* make sure than an output file was given on the command line */
928 if (options->OutputFileName == NULL)
930 fprintf(stderr, "No output file was specified\n");
934 /* read the data file */
935 files = vtkWrapHierarchy_TryReadHierarchyFile(
936 options->InputFileName, files);
938 /* read in all the prior files */
939 for (i = 1; i < options->NumberOfFiles; i++)
941 lines = vtkWrapHierarchy_TryReadHierarchyFile(
942 options->Files[i], lines);
945 /* merge the files listed in the data file */
946 for (i = 0; files[i] != NULL; i++)
948 /* look for semicolon that marks the module name */
949 module_name = files[i];
950 while(*module_name != ';' && *module_name != '\0') { module_name++; };
951 if (*module_name == ';') { *module_name++ = '\0'; }
953 /* look for semicolon that marks start of flags */
955 while(*flags != ';' && *flags != '\0') { flags++; };
956 if (*flags == ';') { *flags++ = '\0'; }
958 lines = vtkWrapHierarchy_TryParseHeaderFile(
959 files[i], module_name, flags, lines);
962 /* sort the lines to ease lookups in the file */
963 for (n = 0; lines[n]; n++) { ; };
964 qsort(lines, n, sizeof(char *), &string_compare);
966 /* write the file, if it has changed */
967 vtkWrapHierarchy_TryWriteHierarchyFile(options->OutputFileName, lines);
969 for (j = 0; j < n; j++)