Salome HOME
CMake: porting module to the new CMake procedure.
[modules/paravis.git] / src / VTKWrapping / ParaView / vtkWrapHierarchy.c
1 /*=========================================================================
2
3   Program:   Visualization Toolkit
4   Module:    vtkWrapHierarchy.c
5
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
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.
13
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16   Copyright (c) 2010 David Gobbi.
17
18   Contributed to the VisualizationToolkit by the author in June 2010
19   under the terms of the Visualization Toolkit 2008 copyright.
20 -------------------------------------------------------------------------*/
21
22 /**
23  The vtkWrapHierarchy program builds a text file that describes the
24  class hierarchy.
25  For each class, the output file will have a line in the following
26  format:
27
28  classname [ : superclass ] ; header.h ; kit [; flags]
29
30  For each enum type,
31
32  enumname : enum ; header.h ; kit [; flags]
33
34  For each typedef,
35
36  name = [2][3]* const int ; header.h ; kit [; flags]
37
38 */
39
40 #include "vtkParse.h"
41 #include "vtkParseData.h"
42 #include "vtkParseMain.h"
43 #include "vtkParsePreprocess.h"
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 #ifdef _WIN32
49 # include <windows.h>
50 #else
51 # include <unistd.h>
52 #endif
53
54 /**
55  * Helper to append a text line to an array of lines
56  */
57 static char **append_unique_line(char **lines, char *line, size_t *np)
58 {
59   size_t l, n;
60
61   n = *np;
62
63   /* check to make sure this line isn't a duplicate */
64   for (l = 0; l < n; l++)
65     {
66     if (strcmp(line, lines[l]) == 0)
67       {
68       break;
69       }
70     }
71   if (l == n)
72     {
73     /* allocate more memory if n+1 is a power of two */
74     if (((n+1) & n) == 0)
75       {
76       lines = (char **)realloc(lines, (n+1)*2*sizeof(char *));
77       }
78
79     lines[n] = (char *)malloc(strlen(line)+1);
80     strcpy(lines[n++], line);
81     lines[n] = NULL;
82     }
83
84   *np = n;
85   return lines;
86 }
87
88 /**
89  * Helper to append to a line, given the end marker
90  */
91 static char *append_to_line(
92   char *line, const char *text, size_t *pos, size_t *maxlen)
93 {
94   size_t n;
95
96   n = strlen(text);
97
98   if ((*pos) + n + 1 > (*maxlen))
99     {
100     *maxlen = ((*pos) + n + 1 + 2*(*maxlen));
101     line = (char *)realloc(line, (*maxlen));
102     }
103
104   strcpy(&line[*pos], text);
105   *pos = (*pos) + n;
106
107   return line;
108 }
109
110 /**
111  * Append scope to line
112  */
113 static char *append_scope_to_line(
114   char *line, size_t *m, size_t *maxlen, const char *scope)
115 {
116   if (scope && scope[0] != '\0')
117     {
118     line = append_to_line(line, scope, m, maxlen);
119     line = append_to_line(line, "::", m, maxlen);
120     }
121
122   return line;
123 }
124
125 /**
126  * Append template info
127  */
128 static char *append_template_to_line(
129   char *line, size_t *m, size_t *maxlen, TemplateInfo *template_args)
130 {
131   ValueInfo *arg;
132   int j;
133
134   line = append_to_line(line, "<", m, maxlen);
135
136   for (j = 0; j < template_args->NumberOfParameters; j++)
137     {
138     arg = template_args->Parameters[j];
139     if (arg->Name)
140       {
141       line = append_to_line(line, arg->Name, m, maxlen);
142       }
143     if (arg->Value && arg->Value[0] != '\n')
144       {
145       line = append_to_line(line, "=", m, maxlen);
146       line = append_to_line(line, arg->Value, m, maxlen);
147       }
148     if (j+1 < template_args->NumberOfParameters)
149       {
150       line = append_to_line(line, ",", m, maxlen);
151       }
152     }
153
154   line = append_to_line(line, ">", m, maxlen);
155
156   return line;
157 }
158
159 /**
160  * Append class info
161  */
162 static char *append_class_to_line(
163   char *line, size_t *m, size_t *maxlen, ClassInfo *class_info)
164 {
165   int j;
166
167   line = append_to_line(line, class_info->Name, m, maxlen);
168
169   if (class_info->Template)
170     {
171     line = append_template_to_line(line, m, maxlen, class_info->Template);
172     }
173
174   line = append_to_line(line, " ", m, maxlen);
175
176   if (class_info->NumberOfSuperClasses)
177     {
178     line = append_to_line(line, ": ", m, maxlen);
179     }
180
181   for (j = 0; j < class_info->NumberOfSuperClasses; j++)
182     {
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)
186       {
187       line = append_to_line(line, ", ", m, maxlen);
188       }
189     }
190
191   return line;
192 }
193
194 /**
195  * Append enum info
196  */
197 static char *append_enum_to_line(
198   char *line, size_t *m, size_t *maxlen, EnumInfo *enum_info)
199 {
200   line = append_to_line(line, enum_info->Name, m, maxlen);
201   line = append_to_line(line, " : enum ", m, maxlen);
202
203   return line;
204 }
205
206 /**
207  * Append the trailer, i.e. the filename and flags
208  */
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)
212 {
213   line = append_to_line(line, "; ", m, maxlen);
214   line = append_to_line(line, header_file, m, maxlen);
215
216   line = append_to_line(line, " ; ", m, maxlen);
217   line = append_to_line(line, module_name, m, maxlen);
218
219   if (flags && flags[0] != '\0')
220     {
221     line = append_to_line(line, " ; ", m, maxlen);
222     line = append_to_line(line, flags, m, maxlen);
223     }
224
225   return line;
226 }
227
228 /**
229  * Append typedef info
230  */
231 static char *append_typedef_to_line(
232   char *line, size_t *m, size_t *maxlen, ValueInfo *typedef_info)
233 {
234   unsigned int type;
235   int ndims;
236   int dim;
237
238   line = append_to_line(line, typedef_info->Name, m, maxlen);
239   line = append_to_line(line, " = ", m, maxlen);
240
241   type = typedef_info->Type;
242
243   if ((type & VTK_PARSE_REF) != 0)
244     {
245     line = append_to_line(line, "&", m, maxlen);
246     }
247
248   ndims = typedef_info->NumberOfDimensions;
249
250   for (dim = 0; dim < ndims; dim++)
251     {
252     line = append_to_line(line, "[", m, maxlen);
253     line = append_to_line(line, typedef_info->Dimensions[dim],
254                           m, maxlen);
255     line = append_to_line(line, "]", m, maxlen);
256     }
257
258   type = (type & VTK_PARSE_POINTER_MASK);
259   if (ndims > 0 && (type & VTK_PARSE_POINTER_LOWMASK) == VTK_PARSE_ARRAY)
260     {
261     type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
262     }
263   else if (ndims == 1)
264     {
265     type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
266     }
267
268   /* pointers are printed after brackets, and are intentionally
269    * printed in reverse order as compared to C++ declarations */
270   while (type)
271     {
272     unsigned int bits = (type & VTK_PARSE_POINTER_LOWMASK);
273     type = ((type >> 2) & VTK_PARSE_POINTER_MASK);
274
275     if (bits == VTK_PARSE_POINTER)
276       {
277       line = append_to_line(line, "*", m, maxlen);
278       }
279     else if (bits == VTK_PARSE_CONST_POINTER)
280       {
281       line = append_to_line(line, "const*", m, maxlen);
282       }
283     else
284       {
285       line = append_to_line(line, "[]", m, maxlen);
286       }
287     }
288
289   if (line[*m-1] != ' ')
290     {
291     line = append_to_line(line, " ", m, maxlen);
292     }
293
294   if ((type & VTK_PARSE_CONST) != 0)
295     {
296     line = append_to_line(line, "const ", m, maxlen);
297     }
298
299   line = append_to_line(line, typedef_info->Class, m, maxlen);
300   line = append_to_line(line, " ", m, maxlen);
301
302   return line;
303 }
304
305 /**
306  * Append all types in a class
307  */
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)
311 {
312   int i;
313   const char *tmpflags;
314   char *new_scope;
315   char *line;
316   size_t m, n, maxlen;
317   size_t scope_m, scope_maxlen;
318
319   /* append the name to the scope */
320   new_scope = 0;
321   n = 0;
322   m = 0;
323   if (scope)
324     {
325     n = strlen(scope);
326     }
327   if (data->Name)
328     {
329     m = strlen(data->Name);
330     }
331   if (m && (n || data->Template))
332     {
333     scope_maxlen = n + m + 3;
334     scope_m = 0;
335     new_scope = (char *)malloc(scope_maxlen);
336     new_scope[0] = '\0';
337     if (n)
338       {
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);
341       }
342     new_scope = append_to_line(new_scope, data->Name, &scope_m, &scope_maxlen);
343     if (data->Template)
344       {
345       new_scope = append_template_to_line(
346         new_scope, &scope_m, &scope_maxlen, data->Template);
347       }
348     scope = new_scope;
349     }
350   else if (m)
351     {
352     scope = data->Name;
353     }
354
355   /* start with a buffer of 15 chars and grow from there */
356   maxlen = 15;
357   m = 0;
358   line = (char *)malloc(maxlen);
359
360   /* add a line for each type that is found */
361   for (i = 0; i < data->NumberOfItems; i++)
362     {
363     m = 0;
364     line[m] = '\0';
365
366     tmpflags = 0;
367
368     if (data->Items[i].Type == VTK_CLASS_INFO ||
369         data->Items[i].Type == VTK_STRUCT_INFO)
370       {
371       ClassInfo *class_info =
372         data->Classes[data->Items[i].Index];
373
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";
377       }
378     else if (data->Items[i].Type == VTK_ENUM_INFO)
379       {
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]);
383       }
384     else if (data->Items[i].Type == VTK_TYPEDEF_INFO)
385       {
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]);
389       }
390     else
391       {
392       /* unhandled file element */
393       continue;
394       }
395
396     /* append filename and flags */
397     line = append_trailer(
398       line, &m, &maxlen, header_file, module_name, tmpflags);
399
400     /* append the line to the file */
401     lines = append_unique_line(lines, line, np);
402
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)
407       {
408       lines = append_class_contents(lines, np,
409         data->Classes[data->Items[i].Index],
410         scope, header_file, module_name);
411       }
412     }
413
414   free(line);
415
416   if (new_scope != 0)
417     {
418     free(new_scope);
419     }
420
421   return lines;
422 }
423
424
425 /**
426  * Append all types in a namespace
427  */
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,
431   const char *flags)
432 {
433   int i;
434   const char *tmpflags;
435   char *line;
436   char *new_scope;
437   size_t n, m, maxlen;
438
439   /* append the name to the scope */
440   new_scope = 0;
441   n = 0;
442   m = 0;
443   if (scope)
444     {
445     n = strlen(scope);
446     }
447   if (data->Name)
448     {
449     m = strlen(data->Name);
450     }
451   if (m && n)
452     {
453     new_scope = (char *)malloc(m + n + 3);
454     if (n)
455       {
456       strncpy(new_scope, scope, n);
457       new_scope[n++] = ':';
458       new_scope[n++] = ':';
459       }
460     strncpy(&new_scope[n], data->Name, m);
461     new_scope[n+m] = '\0';
462     scope = new_scope;
463     }
464   else if (m)
465     {
466     scope = data->Name;
467     }
468
469   /* start with a buffer of 15 chars and grow from there */
470   maxlen = 15;
471   m = 0;
472   line = (char *)malloc(maxlen);
473
474   /* add a line for each type that is found */
475   for (i = 0; i < data->NumberOfItems; i++)
476     {
477     tmpflags = 0;
478     m = 0;
479     line[m] = '\0';
480
481     if (data->Items[i].Type == VTK_CLASS_INFO ||
482         data->Items[i].Type == VTK_STRUCT_INFO)
483       {
484       ClassInfo *class_info =
485         data->Classes[data->Items[i].Index];
486
487       /* all but the main class in each file is excluded from wrapping */
488       tmpflags = "WRAP_EXCLUDE";
489       if (class_info == main_class)
490         {
491         tmpflags = flags;
492         }
493
494       line = append_scope_to_line(line, &m, &maxlen, scope);
495       line = append_class_to_line(line, &m, &maxlen, class_info);
496       }
497     else if (data->Items[i].Type == VTK_ENUM_INFO)
498       {
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]);
502       }
503     else if (data->Items[i].Type == VTK_TYPEDEF_INFO)
504       {
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]);
508       }
509     else if (data->Items[i].Type != VTK_NAMESPACE_INFO)
510       {
511       /* unhandled file element */
512       continue;
513       }
514
515     if (data->Items[i].Type != VTK_NAMESPACE_INFO)
516       {
517       /* append filename and flags */
518       line = append_trailer(
519         line, &m, &maxlen, header_file, module_name, tmpflags);
520
521       /* append the line to the file */
522       lines = append_unique_line(lines, line, np);
523       }
524
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)
529       {
530       lines = append_class_contents(lines, np,
531         data->Classes[data->Items[i].Index],
532         scope, header_file, module_name);
533       }
534
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)
538       {
539       lines = append_namespace_contents(lines, np,
540         data->Namespaces[data->Items[i].Index], 0,
541         scope, header_file, module_name, "WRAP_EXCLUDE");
542       }
543     }
544
545   free(line);
546
547   if (new_scope != 0)
548     {
549     free(new_scope);
550     }
551
552   return lines;
553 }
554
555 /**
556  * Read a header file with vtkParse.tab.c
557  *
558  * If "lines" is provided, the file contents
559  * will be appended to them.
560  */
561 static char **vtkWrapHierarchy_ParseHeaderFile(
562   FILE *fp, const char *filename, const char *module_name,
563   const char *flags, char **lines)
564 {
565   FileInfo *data;
566   const char *header_file;
567   size_t k, n;
568
569   /* start with just a single output line and grow from there */
570   if (lines == NULL)
571     {
572     lines = (char **)malloc(sizeof(char *));
573     lines[0] = NULL;
574     }
575
576   /* always ignore BTX markers when building hierarchy files */
577   vtkParse_SetIgnoreBTX(1);
578
579   /* the "concrete" flag doesn't matter, just set to zero */
580   data = vtkParse_ParseFile(filename, fp, stderr);
581
582   if (!data)
583     {
584     free(lines);
585     return 0;
586     }
587
588   /* find the last line in "lines" */
589   n = 0;
590   while (lines[n] != NULL)
591     {
592     n++;
593     }
594
595   k = strlen(data->FileName) - 1;
596   while (k > 0 && data->FileName[k-1] != '/' && data->FileName[k-1] != '\\')
597     {
598     k--;
599     }
600   header_file = &data->FileName[k];
601
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);
606
607   vtkParse_Free(data);
608
609   return lines;
610 }
611
612 /**
613  * Read a hierarchy file into "lines" without duplicating lines
614  */
615 static char **vtkWrapHierarchy_ReadHierarchyFile(FILE *fp, char **lines)
616 {
617   char *line;
618   size_t maxlen = 15;
619   size_t i, n;
620
621   line = (char *)malloc(maxlen);
622
623   if (lines == NULL)
624     {
625     lines = (char **)malloc(sizeof(char *));
626     lines[0] = NULL;
627     }
628
629   while (fgets(line, (int)maxlen, fp))
630     {
631     n = strlen(line);
632
633     /* if buffer not long enough, increase it */
634     while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
635       {
636       maxlen *= 2;
637       line = (char *)realloc(line, maxlen);
638       if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
639       n += strlen(&line[n]);
640       }
641
642     while (n > 0 && isspace(line[n-1]))
643       {
644       n--;
645       }
646     line[n] = '\0';
647
648     if (line[0] == '\0')
649       {
650       continue;
651       }
652
653     for (i = 0; lines[i] != NULL; i++)
654       {
655       if (strcmp(line, lines[i]) == 0)
656         {
657         break;
658         }
659       }
660
661     if (lines[i] == NULL)
662       {
663       /* allocate more memory if n+1 is a power of two */
664       if (((i+1) & i) == 0)
665         {
666         lines = (char **)realloc(lines, (i+1)*2*sizeof(char *));
667         }
668
669       lines[i] = (char *)malloc(n+1);
670       strcpy(lines[i], line);
671       lines[i+1] = NULL;
672       }
673     }
674
675   free(line);
676
677   if (!feof(fp))
678     {
679     free(lines);
680     return 0;
681     }
682
683   return lines;
684 }
685
686 /**
687  * Compare a file to "lines", return 0 if they are different
688  */
689 static int vtkWrapHierarchy_CompareHierarchyFile(FILE *fp, char *lines[])
690 {
691   unsigned char *matched;
692   char *line;
693   size_t maxlen = 15;
694   size_t i, n;
695
696   line = (char *)malloc(maxlen);
697
698   for (i = 0; lines[i] != NULL; i++) { ; };
699   matched = (unsigned char *)malloc(i);
700   memset(matched, 0, i);
701
702   while (fgets(line, (int)maxlen, fp))
703     {
704     n = strlen(line);
705
706     /* if buffer not long enough, increase it */
707     while (n == maxlen-1 && line[n-1] != '\n' && !feof(fp))
708       {
709       maxlen *= 2;
710       line = (char *)realloc(line, maxlen);
711       if (!fgets(&line[n], (int)(maxlen-n), fp)) { break; }
712       n += strlen(&line[n]);
713       }
714
715     while (n > 0 && isspace(line[n-1]))
716       {
717       n--;
718       }
719     line[n] = '\0';
720
721     if (line[0] == '\0')
722       {
723       continue;
724       }
725
726     for (i = 0; lines[i] != NULL; i++)
727       {
728       if (strcmp(line, lines[i]) == 0)
729         {
730         break;
731         }
732       }
733
734     if (lines[i] == NULL)
735       {
736       free(matched);
737       return 0;
738       }
739
740     matched[i] = 1;
741     }
742
743   for (i = 0; lines[i] != NULL; i++)
744     {
745     if (matched[i] == 0)
746       {
747       free(matched);
748       return 0;
749       }
750     }
751
752   free(line);
753   free(matched);
754
755   if (!feof(fp))
756     {
757     return 0;
758     }
759
760   return 1;
761 }
762
763 /**
764  * Write "lines" to a hierarchy file
765  */
766 static int vtkWrapHierarchy_WriteHierarchyFile(FILE *fp, char *lines[])
767 {
768   size_t i;
769
770   for (i = 0; lines[i] != NULL; i++)
771     {
772     if (fprintf(fp, "%s\n", lines[i]) < 0)
773       {
774       return 0;
775       }
776     }
777
778   return 1;
779 }
780
781 /**
782  * Try to parse a header file, print error and exit if fail
783  */
784 static char **vtkWrapHierarchy_TryParseHeaderFile(
785   const char *file_name, const char *module_name,
786   const char *flags, char **lines)
787 {
788   FILE *input_file;
789
790   input_file = fopen(file_name, "r");
791
792   if (!input_file)
793     {
794     fprintf(stderr, "vtkWrapHierarchy: couldn't open file %s\n",
795             file_name);
796     exit(1);
797     }
798
799   lines = vtkWrapHierarchy_ParseHeaderFile(
800                  input_file, file_name, module_name, flags, lines);
801
802   if (!lines)
803     {
804     fclose(input_file);
805     exit(1);
806     }
807   fclose(input_file);
808
809   return lines;
810 }
811
812 /**
813  * Try to read a file, print error and exit if fail
814  */
815 static char **vtkWrapHierarchy_TryReadHierarchyFile(
816   const char *file_name, char **lines)
817 {
818   FILE *input_file;
819
820   input_file = fopen(file_name, "r");
821   if (!input_file)
822     {
823     fprintf(stderr, "vtkWrapHierarchy: couldn't open file %s\n",
824             file_name);
825     exit(1);
826     }
827
828   lines = vtkWrapHierarchy_ReadHierarchyFile(input_file, lines);
829   if (!lines)
830     {
831     fclose(input_file);
832     fprintf(stderr, "vtkWrapHierarchy: error reading file %s\n",
833             file_name);
834     exit(1);
835     }
836   fclose(input_file);
837
838   return lines;
839 }
840
841 /**
842  * Try to write a file, print error and exit if fail
843  */
844 static int vtkWrapHierarchy_TryWriteHierarchyFile(
845   const char *file_name, char *lines[])
846 {
847   FILE *output_file;
848   int matched = 0;
849
850   output_file = fopen(file_name, "r");
851   if (output_file && vtkWrapHierarchy_CompareHierarchyFile(output_file, lines))
852     {
853     matched = 1;
854     }
855   if (output_file)
856     {
857     fclose(output_file);
858     }
859
860   if (!matched)
861     {
862     int tries = 1;
863     output_file = fopen(file_name, "w");
864     while (!output_file && tries < 5)
865       {
866       /* There are two CMAKE_CUSTOM_COMMANDS for vtkWrapHierarchy,
867        * make sure they do not collide. */
868       tries++;
869 #ifdef _WIN32
870       Sleep(1000);
871 #else
872       sleep(1);
873 #endif
874       output_file = fopen(file_name, "r+");
875       if (output_file &&
876           vtkWrapHierarchy_CompareHierarchyFile(output_file, lines))
877         {
878         /* if the contents match, no need to write it */
879         fclose(output_file);
880         return 0;
881         }
882       if (output_file)
883         {
884         /* close and open in order to truncate the file */
885         fclose(output_file);
886         output_file = fopen(file_name, "w");
887         }
888       }
889     if (!output_file)
890       {
891       fprintf(stderr, "vtkWrapHierarchy: tried %i times to write %s\n",
892               tries, file_name);
893       exit(1);
894       }
895     if (!vtkWrapHierarchy_WriteHierarchyFile(output_file, lines))
896       {
897       fclose(output_file);
898       fprintf(stderr, "vtkWrapHierarchy: error writing file %s\n",
899               file_name);
900       exit(1);
901       }
902     fclose(output_file);
903     }
904
905   return 0;
906 }
907
908 static int string_compare(const void *vp1, const void *vp2)
909 {
910   return strcmp(*(const char **)vp1, *(const char **)vp2);
911 }
912
913 int main(int argc, char *argv[])
914 {
915   OptionInfo *options;
916   int i;
917   size_t j, n;
918   char **lines = 0;
919   char **files = 0;
920   char *flags;
921   char *module_name;
922
923   /* parse command-line options */
924   vtkParse_MainMulti(argc, argv);
925   options = vtkParse_GetCommandLineOptions();
926
927   /* make sure than an output file was given on the command line */
928   if (options->OutputFileName == NULL)
929     {
930     fprintf(stderr, "No output file was specified\n");
931     exit(1);
932     }
933
934   /* read the data file */
935   files = vtkWrapHierarchy_TryReadHierarchyFile(
936     options->InputFileName, files);
937
938   /* read in all the prior files */
939   for (i = 1; i < options->NumberOfFiles; i++)
940     {
941     lines = vtkWrapHierarchy_TryReadHierarchyFile(
942       options->Files[i], lines);
943     }
944
945   /* merge the files listed in the data file */
946   for (i = 0; files[i] != NULL; i++)
947     {
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'; }
952
953     /* look for semicolon that marks start of flags */
954     flags = module_name;
955     while(*flags != ';' && *flags != '\0') { flags++; };
956     if (*flags == ';') { *flags++ = '\0'; }
957
958     lines = vtkWrapHierarchy_TryParseHeaderFile(
959       files[i], module_name, flags, lines);
960     }
961
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);
965
966   /* write the file, if it has changed */
967   vtkWrapHierarchy_TryWriteHierarchyFile(options->OutputFileName, lines);
968
969   for (j = 0; j < n; j++)
970     {
971     free(lines[j]);
972     }
973
974   free(files);
975   free(lines);
976   return 0;
977 }