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