File Coverage

Wcl-gen
Criterion Covered Total %
statement 49 87 56.3
branch 2 12 16.6
condition n/a
subroutine 6 7 85.7
pod n/a
total 57 106 53.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #
3             # generate the SWIG input file by preprocessing the X and Motif header files
4             #
5             # This was developed incrementally, by feeding the output to SWIG,
6             # seeing what it did not like, and developing PERL regular expressions
7             # to do the proper massaging.
8             #
9             # Porting to another platform will require changes to the way that the
10             # preprocessor is invoked (including possibly a different set of
11             # header files) and some new regexp processing.
12             #
13              
14 1         5 $INFILE = $ARGV[0];
15 1         2 $NUM_XTPROCS = $ARGV[1];
16              
17 1         5 read_input();
18 1         11 discard_uninteresting_header_files();
19 1         7 make_defines();
20 1         11 make_output();
21 1         26 add_xtprocs();
22 1         6 add_standard_member_functions();
23              
24             # helper function to emit SWIG input lines
25             sub emit
26             {
27 0     0   0 my($s) = @_;
28 0         0 $s =~ s#^[^\S\n]*\n##;
29 0         0 $s =~ s#^[^\S\n]+\Z##m;
30 0         0 $s =~ m#^([^\S\n]*\|?)#;
31 0         0 my $x = quotemeta $1;
32 0         0 $s =~ s#^$x##gm;
33 0         0 print STDOUT $s;
34             }
35              
36             # generate and read in the input
37             sub read_input
38             {
39             # run the preprocessor on the header files in which we are interested
40 1     1   37746 open(IN, q{
41             set -x
42             TEMP=/tmp/temp.wcl-gen.$$.c
43             grep '^#include' } . $INFILE . q{ >$TEMP
44             $CC -E $CCFLAGS $TEMP
45             rm -f $TEMP
46             |});
47              
48             # read it all into a string
49 1         37 $x = $/;
50 1         763 undef $/;
51 1         70046 $data = ;
52 1         20 $/ = $x;
53              
54 1         87 close(IN);
55             }
56              
57             # chuck header files not apropos to this application
58             sub discard_uninteresting_header_files
59             {
60             # remove header files we are not interested in
61             # this is undoubtedly somewhat preprocessor dependent
62 1     1   13 $data =~ s@^#line @# @gm;
63 1         23 $data =~ s@^# \d+\n@@gm;
64 1         31 $data =~ s@^# \d+ "/usr/include/(?!X).*\n(([^#\n].*)?\n)*@@gm;
65 1         6 $data =~ s@^# \d+ "/usr/lib/.*\n(([^#\n].*)?\n)*@@gm;
66 1         3 $data =~ s@^# \d+ "/usr/local/lib/.*\n(([^#\n].*)?\n)*@@gm;
67 1         4 $data =~ s@^# \d+ "/usr/X11R6/include/.*P[.]h".*\n(([^#\n].*)?\n)*@@gm;
68             }
69              
70             # pull #defines out of input; they disappear from cpp output
71             sub make_defines
72             {
73             # extract #define constants from header files mentioned in input
74 1     1   24 while ($data =~ m@^# \d+ "(\S+)"@gm) {
75 4 100       38 next unless !$seen{$1}++;
76 2         101 open(IN, "<$1");
77 2         17 while () {
78             # define with no arguments
79 0 0       0 next unless /^\s*#\s*define\s+\w+\s+/;
80             # strip trailing comments
81 0         0 s#\s*/\*((?!\*/).)*\*/[^\S\n]$##;
82             # empty
83 0 0       0 next if /^\s*#\s*define\s+\w+\s*$/;
84             # strings
85 0 0       0 next if /^\s*#\s*define\s+\w+\s+"[^"]*"\s*$/; #"
86             # integer expressions
87 0 0       0 next unless (/^
88             \s*\#\s*define\s+(\w+)\s+
89             ((
90             -?\d+L? |
91             -?0[xX][0-9a-fA-F]+L? |
92             [()|] |
93             << |
94             >>
95             )\s*)+
96             $/x);
97 0         0 print STDOUT "#ifndef $1\n";
98 0         0 print STDOUT;
99 0         0 print STDOUT "#endif\n";
100             }
101 2         11 close(IN);
102             }
103             }
104              
105             # massage input header files into something that SWIG can digest
106             sub make_output
107             {
108             # chuck preprocessor lines
109 1     1   14 $data =~ s@^#.*\n@@gm;
110              
111             # chuck blank lines
112 1         3 $data =~ s/^[^\S\n]*\n//gm;
113              
114             # eliminate trailing white space
115 1         2 $data =~ s/[^\S\n]+\n/\n/g;
116              
117             # convert multiple white space to single blank
118 1         1 $data =~ s/[^\S\n]+/ /g;
119              
120             # eliminate keywords not known to SWIG
121 1         4 $data =~ s#\b(register|__signed||unsigned)\b##gm;
122              
123             # rename C++ reserved words
124 1         2 $data =~ s#\b(new|class)\b#PASS_THROUGH_SWIG_$1#gm;
125              
126             # eliminate global arrays
127 1         1 $data =~ s/^\s*(typedef|extern)( \w+)+ \w+\[\];\n//mg;
128              
129             # eliminate vararg declarations
130 1         3 $data =~ s/^(extern|typedef)( \w+)? \(?\*?\w+\)?\s*\([^)]*,\s*\.\.\.\s*\)\s*;\s*\n//mg;
131              
132             # eliminate function pointer declarations
133 1         3 $data =~ s/^extern \S+ \(\*\w+\(((?!\)\s*;)(.|\n))*\)\s*;\n//mg;
134              
135             # eliminate functions that get passed function pointers
136 1         5 $data =~ s/^extern( \S+)? \*?\w+\(((?!\)\s*;)(.|\n))*,\s*\w+\s*\(\s*\*\s*\)\s*\(((?!\)\s*;)(.|\n))*\)\s*;\n//mg;
137              
138             # various other special cases
139 1         2 $data =~ s/^extern( \w+)? WcWidgetResourcesInitialize\s*\(\s*[^;]*;\n//m;
140 1         2 $data =~ s/^typedef struct( \S+)?\s*\{\n(([^}\n].*)?\n)*\}\s*XImage;\n//m;
141 1         2 $data =~ s/^typedef struct( \S+)?\s*\{\n(([^}\n].*)?\n)*\}\s*XExtData;\n//m;
142 1         1 $data =~ s/^typedef struct( \S+)?\s*\{\n(([^}\n].*)?\n)*\}\s*XSizeHints;\n//m;
143 1         2 $data =~ s/^typedef struct( \S+)?\s*\{\n(([^}\n].*)?\n)*\}\s*\*_XPrivDisplay;\n//m;
144             # added for aix 3.2.5 and HPUX 10
145 1         2 $data =~ s/^typedef struct( \S+)?\s*\{\n(([^}\n].*)?\n)*\}\s*\*GC;\n//m;
146 1         2 $data =~ s/^void XmpChangeNavigationType \( Widget \)\s*;\n//m;
147 1         2 $data =~ s/^extern void ToggleCursorGC\s*\([^()]*\)\s*;\n//m;
148             # seems to be in header file but missing from libraries in RedHat Motif
149 1         2 $data =~ s/^extern \S+ XmCSTextGetTextPath\s*\([^()]*\)\s*;\s*\n//m;
150 1         2 $data =~ s/^extern \S+ XmCSTextSetTextPath\s*\([^()]*\)\s*;\s*\n//m;
151 1         2 $data =~ s/^extern \S+ XmCSTextMarkRedraw\s*\([^()]*\)\s*;\s*\n//m;
152              
153             # done massaging
154 1         13 print STDOUT $data;
155             }
156              
157             # create Xt*Proc() interface
158             sub add_xtprocs
159             {
160 1     1   7 while ($data =~ m#typedef\s+(\S+)\s*\(\s*\*\s*(Xt\w+Proc)\s*\)\s*\(([^()]*)\)#g) {
161 0           my($type, $name, $args) = ($1, $2, $3);
162 0           my @args = split(/\s*,\s*/, $args);
163 0           my $arg;
164             my @x;
165 0           my @argnames;
166 0           my $i = 0;
167 0           for $arg (@args) {
168 0           push(@x, "$arg arg$i");
169 0           push(@argnames, ", arg$i");
170 0           ++$i;
171             }
172 0           $args = join(",\n", @x);
173              
174             # emit the standard functions
175 0           emit(qq(
176             \%{
177             ));
178 0           emit(qq(
179             static int xtproc_key_$name;
180              
181             static $type
182             Standard$name(int function_number, $args)
183             {
184             char *perl_procedure_name =
185             MapAg_Find(_X11_Wcl_agent, &xtproc_key_$name, function_number, 0);
186             if (perl_procedure_name) {
187             char *argv[1];
188             argv[0] = 0;
189             /* do the callback, discarding any results */
190             perl_call_argv(perl_procedure_name, G_DISCARD, argv);
191             }
192             }
193              
194             ));
195 0           for ($i=0; $i<$NUM_XTPROCS; ++$i) {
196 0           emit(qq(
197             static $type
198             Standard$name$i($args)
199             {
200             Standard$name($i @argnames);
201             }
202              
203             ));
204             }
205              
206             # emit the table of standard functions
207 0           emit(qq(
208             static $name table_$name\[] = {
209             ));
210 0           for ($i=0; $i<$NUM_XTPROCS; ++$i) {
211 0           emit(qq(
212             Standard$name$i,
213             ));
214             }
215 0           emit(qq(
216             };
217             ));
218 0           emit(qq(
219             \%}
220             ));
221              
222             # emit allocator for standard functions
223 0           emit(qq(
224             \%inline \%{
225             $name
226             Make$name(char *perl_procedure_name)
227             {
228             static int counter = 0;
229             if ((counter + 1) < $NUM_XTPROCS) {
230             char *x = strdup(perl_procedure_name);
231             MapAg_Define(_X11_Wcl_agent, &xtproc_key_$name, counter, 0, x);
232             return(table_$name\[counter++]);
233             } else {
234             return(($name)0);
235             }
236             }
237             \%}
238              
239             ));
240             }
241             }
242              
243             # add constructors, destructors and other member functions to structs
244             # found in the input header files of interest
245             sub add_standard_member_functions
246             {
247 1     1     while ($data =~ m/
248             typedef \s*
249             (?:struct|union)(?:\s+\S+)? \s*
250             { (?:
251             [^{}]+ |
252             { (?:
253             [^{}]+ |
254             { (?:
255             [^{}]+
256             )* }
257             )* }
258             )* } \s*
259             (\*?\w+)
260             /mgx) {
261 0           $struct = $1;
262 0 0         next unless $struct =~ /^\w+$/;
263 0           emit(qq(
264             \%addmethods $struct {
265             $struct(int address = 0, int count = 0) {
266             return(($struct *)_X11_Wcl_do_constructor(address, count, sizeof($struct)));
267             }
268             ~$struct() {
269             _X11_Wcl_do_destructor((char *)self);
270             }
271             $struct *
272             idx(int i) {
273             return(self + i);
274             }
275             };
276              
277             ));
278             }
279             }