Mercurial > hg > xemacs-beta
comparison lib-src/make-mswin-unicode.pl @ 5125:b5df3737028a ben-lisp-object
merge
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Wed, 24 Feb 2010 01:58:04 -0600 |
parents | 7eec2a1f3412 |
children | 308d34e9f07d |
comparison
equal
deleted
inserted
replaced
5124:623d57b7fbe8 | 5125:b5df3737028a |
---|---|
1 : #-*- Perl -*- | 1 : #-*- Perl -*- |
2 | 2 |
3 ### make-mswin-unicode --- generate Unicode-encapsulation code for MS Windows | 3 ### make-mswin-unicode --- generate Unicode-encapsulation code for MS Windows |
4 | 4 |
5 ## Copyright (C) 2001, 2002, 2004 Ben Wing. | 5 ## Copyright (C) 2001, 2002, 2004, 2010 Ben Wing. |
6 | 6 |
7 ## Author: Ben Wing <ben@xemacs.org> | 7 ## Author: Ben Wing <ben@xemacs.org> |
8 ## Maintainer: Ben Wing <ben@xemacs.org> | 8 ## Maintainer: Ben Wing <ben@xemacs.org> |
9 ## Current Version: 1.0, August 24, 2001 | 9 ## Current Version: 1.0, August 24, 2001 |
10 | 10 |
61 | 61 |
62 file specifies a file to start reading from. | 62 file specifies a file to start reading from. |
63 yes indicates a function to be automatically Unicode-encapsulated. | 63 yes indicates a function to be automatically Unicode-encapsulated. |
64 (All parameters either need no special processing or are LPTSTR or | 64 (All parameters either need no special processing or are LPTSTR or |
65 LPCTSTR.) | 65 LPCTSTR.) |
66 override indidates a function where the prototype can be overridden | |
67 due to errors in Cygwin or Visual Studio. | |
66 soon indicates a function that should be automatically Unicode-encapsulated, | 68 soon indicates a function that should be automatically Unicode-encapsulated, |
67 but we're not ready to process it yet. | 69 but we're not ready to process it yet. |
68 no indicates a function we don't support (it will be #defined to cause | 70 no indicates a function we don't support (it will be #defined to cause |
69 a compile error, with the text after the function included in the | 71 a compile error, with the text after the function included in the |
70 erroneous definition to indicate why we don't support it). | 72 erroneous definition to indicate why we don't support it). |
73 review indicates a function that we still need to review to determine whether | |
74 or how to support it. This has the same effect as `no', with a comment | |
75 indicating that the function needs review. | |
71 skip indicates a function we support manually; only a comment about this | 76 skip indicates a function we support manually; only a comment about this |
72 will be generated. | 77 will be generated. |
73 split indicates a function with a split structure (different versions | 78 split indicates a function with a split structure (different versions |
74 for Unicode and ANSI), but where the only difference is in pointer | 79 for Unicode and ANSI), but where the only difference is in pointer |
75 types, and the actual size does not differ. The structure name | 80 types, and the actual size does not differ. The structure name |
100 my $slurp; | 105 my $slurp; |
101 | 106 |
102 my ($cout, $hout, $dir) = ($options{"c-output"}, | 107 my ($cout, $hout, $dir) = ($options{"c-output"}, |
103 $options{"h-output"}, | 108 $options{"h-output"}, |
104 $options{"includedir"}); | 109 $options{"includedir"}); |
110 | |
111 $dir = '/usr/include/w32api' if !$dir && -f '/usr/include/w32api/windows.h'; | |
112 | |
105 if (!$dir) | 113 if (!$dir) |
106 { | 114 { |
107 for my $sdkroot (("WindowsSdkDir", "MSSdk", "MSVCDIR")) | 115 for my $sdkroot (("WindowsSdkDir", "MSSdk", "MSVCDIR")) |
108 { | 116 { |
109 if (defined $ENV{$sdkroot}) { | 117 if (defined $ENV{$sdkroot}) { |
113 } | 121 } |
114 unless (defined $dir) | 122 unless (defined $dir) |
115 { | 123 { |
116 die "Can't find the Windows SDK headers; run vcvars32.bat from your MSVC installation, or setenv.cmd from the Platform SDK installation"; | 124 die "Can't find the Windows SDK headers; run vcvars32.bat from your MSVC installation, or setenv.cmd from the Platform SDK installation"; |
117 } | 125 } |
118 $dir.='/include'; | |
119 } | 126 } |
127 $dir.='/include' if ((-f $dir.'/include/WINDOWS.H') || | |
128 (-f $dir.'/include/windows.h')); | |
120 die "Can't find MSVC include files in \"$dir\"" unless ((-f $dir.'/WINDOWS.H') || (-f $dir.'/windows.h')); | 129 die "Can't find MSVC include files in \"$dir\"" unless ((-f $dir.'/WINDOWS.H') || (-f $dir.'/windows.h')); |
121 | 130 |
122 open (COUT, ">$cout") or die "Can't open C output file $cout: $!"; | 131 open (COUT, ">$cout") or die "Can't open C output file $cout: $!"; |
123 open (HOUT, ">$hout") or die "Can't open C output file $hout: $!"; | 132 open (HOUT, ">$hout") or die "Can't open C output file $hout: $!"; |
124 | 133 |
146 my %processed; | 155 my %processed; |
147 my %bracket; | 156 my %bracket; |
148 | 157 |
149 my $current_file; | 158 my $current_file; |
150 my @current_bracket; | 159 my @current_bracket; |
160 | |
161 my ($ws_re, $must_ws_re, $tok_ch) = | |
162 ("\\s*", "\\s+", "\\w"); | |
163 # unfortunately there is no surefire way short of | |
164 # parsing all include files for typedefs to | |
165 # distinguish types from parameters, and prototypes | |
166 # appear in the include files both with and without | |
167 # parameters -- the latter kinds appear in a very | |
168 # different style and were obviously added later. so | |
169 # we rely on the fact that defined types are all | |
170 # upper-case, and parameters generally are not, and | |
171 # special-case the exceptions. | |
172 my $typeword_re = | |
173 # note the negative lookahead assertions: the first | |
174 # one excludes the words "X" and "Y" from type | |
175 # words, since they appear as parameter names in | |
176 # CreateWindowEx; the second prevents "void | |
177 # *Argument" from being parsed as a type "void *A" | |
178 # followed by a parameter "rgument". | |
179 "(?:(?!(?:X\\b|Y\\b))(?:unsigned|int|long|const|short|va_list|[A-Z_0-9]+)(?!${tok_ch}))"; | |
180 my $typetoken_re = "(?:$typeword_re$ws_re\\**$ws_re)"; | |
181 # Regexp matching a particular argument | |
182 my $arg_re = "(?:(?:$typetoken_re+)(?:${tok_ch}+)?(?: OPTIONAL)?)"; | |
183 # Same, but with groups to match the type and name | |
184 my $argmatch_re = "(?:($typetoken_re+)(${tok_ch}+)?(?: OPTIONAL)?)"; | |
185 # regexp matching a parenthesized argument list in a prototype | |
186 my $args_re = "\\(((?:${ws_re}${arg_re}${ws_re},)*${ws_re}${arg_re}${ws_re})\\)"; | |
187 # regexp matching a return type in a protype | |
188 my $rettype_re = "(SHSTDAPI_\\(${tok_ch}+\\)|${tok_ch}" . "[A-Za-z_0-9 \t\n\r\f]*?${tok_ch})"; | |
189 # regexp matching a function name | |
190 my $funname_re = "(${tok_ch}+)"; | |
191 # Regexp matching a function prototype, $1 = rettype, $2 = name, $3 = args | |
192 my $fun_re = "${rettype_re}${ws_re}${funname_re}${ws_re}${args_re};"; | |
193 # Regexp matching a particular Unicode function (ending in ...W) | |
194 my $wfun_re = "${rettype_re}${ws_re}${funname_re}W${ws_re}${args_re};"; | |
195 | |
196 # print "regexp: $wfun_re\n"; | |
151 | 197 |
152 while (<>) | 198 while (<>) |
153 { | 199 { |
154 chomp; | 200 chomp; |
155 # remove trailing CR. #### Should not be necessary! Perl should be | 201 # remove trailing CR. #### Should not be necessary! Perl should be |
167 } | 213 } |
168 elsif ($in_script) | 214 elsif ($in_script) |
169 { | 215 { |
170 next if (m!^//!); | 216 next if (m!^//!); |
171 next if (/^[ \t]*$/); | 217 next if (/^[ \t]*$/); |
172 if (/(file|yes|soon|no|skip|split|begin-bracket|end-bracket)(?: (.*))?/) | 218 if (/(file|yes|soon|no|review|skip|split|begin-bracket|end-bracket|override)(?: (.*))?/) |
173 { | 219 { |
174 my ($command, $parms) = ($1, $2); | 220 my ($command, $parms) = ($1, $2); |
175 if ($command eq "file") | 221 if ($command eq "file") |
176 { | 222 { |
177 $current_file = $parms; | 223 $current_file = $parms; |
190 push @current_bracket, $current_bracket; | 236 push @current_bracket, $current_bracket; |
191 } | 237 } |
192 elsif ($command eq "end-bracket") | 238 elsif ($command eq "end-bracket") |
193 { | 239 { |
194 pop @current_bracket; | 240 pop @current_bracket; |
241 } | |
242 elsif ($command eq "override") | |
243 { | |
244 die "Cannot parse prototype $parms" unless $parms =~ /$wfun_re(?: ?(.*))?/; | |
245 my ($rettype, $fun, $args, $reason) = ($1, $2, $3, $4); | |
246 $files{$current_file}{$fun} = | |
247 [$command, $reason, $rettype, $fun, $args]; | |
248 $bracket{$current_file}{$fun} = | |
249 $current_bracket[$#current_bracket]; | |
195 } | 250 } |
196 else | 251 else |
197 { | 252 { |
198 my ($fun, $reason) = split /\s+/, $parms, 2; | 253 my ($fun, $reason) = split /\s+/, $parms, 2; |
199 $files{$current_file}{$fun} = [$command, $reason]; | 254 $files{$current_file}{$fun} = [$command, $reason]; |
224 (" " x $alignspaceright) . "*/ | 279 (" " x $alignspaceright) . "*/ |
225 /*----------------------------------------------------------------------*/ | 280 /*----------------------------------------------------------------------*/ |
226 | 281 |
227 "; | 282 "; |
228 | 283 |
229 my ($ws_re, $must_ws_re, $tok_ch) = | 284 while ($slurp =~ /$wfun_re/g) |
230 ("\\s*", "\\s+", "\\w"); | |
231 # unfortunately there is no surefire way short of | |
232 # parsing all include files for typedefs to | |
233 # distinguish types from parameters, and prototypes | |
234 # appear in the include files both with and without | |
235 # parameters -- the latter kinds appear in a very | |
236 # different style and were obviously added later. so | |
237 # we rely on the fact that defined types are all | |
238 # upper-case, and parameters generally are not, and | |
239 # special-case the exceptions. | |
240 my $typeword_re = | |
241 # note the negative lookahead assertions: the first | |
242 # one excludes the words "X" and "Y" from type | |
243 # words, since they appear as parameter names in | |
244 # CreateWindowEx; the second prevents "void | |
245 # *Argument" from being parsed as a type "void *A" | |
246 # followed by a parameter "rgument". | |
247 "(?:(?!(?:X\\b|Y\\b))(?:unsigned|int|long|short|va_list|[A-Z_0-9]+)(?!${tok_ch}))"; | |
248 my $typetoken_re = "(?:$typeword_re$ws_re\\**$ws_re)"; | |
249 my $arg_re = "(?:($typetoken_re+)(${tok_ch}+)?(?: OPTIONAL)?)"; | |
250 my $fun_re = "(SHSTDAPI_\\(${tok_ch}+\\)|${tok_ch}" . "[A-Za-z_0-9 \t\n\r\f]*?${tok_ch})${ws_re}(${tok_ch}+)W${ws_re}\\(((${ws_re}${arg_re}${ws_re},)*${ws_re}${arg_re}${ws_re})\\);"; | |
251 | |
252 # print "regexp: $fun_re\n"; | |
253 while ($slurp =~ /$fun_re/g) | |
254 { | 285 { |
255 my ($rettype, $fun, $args) = ($1, $2, $3); | 286 my ($rettype, $fun, $args) = ($1, $2, $3); |
287 | |
288 if ($processed{$fun}) | |
289 { | |
290 print "Warning: Function $fun already seen\n"; | |
291 next; | |
292 } | |
293 | |
256 $processed{$fun} = 1; | 294 $processed{$fun} = 1; |
295 | |
257 print "Processing: $fun"; | 296 print "Processing: $fun"; |
258 | 297 |
259 my ($command, $reason) = ($files{$file}{$fun}[0], $files{$file}{$fun}[1]); | 298 #my ($command, $reason) = ($files{$file}{$fun}[0], $files{$file}{$fun}[1]); |
299 # Fuck perl! There seems to be no way to write something like | |
300 # my ($command, $reason) = @$files{$file}{$fun}; | |
301 # You have to use a temporary var. | |
302 my $filesarr = $files{$file}{$fun}; | |
303 my ($command, $reason) = @$filesarr; | |
260 if (!defined ($command)) | 304 if (!defined ($command)) |
261 { | 305 { |
262 print " (no command found)\n"; | 306 print " (no command found)\n"; |
263 } | 307 } |
264 else | 308 else |
268 if (defined ($bracket)) | 312 if (defined ($bracket)) |
269 { | 313 { |
270 print HOUT "#if $bracket\n"; | 314 print HOUT "#if $bracket\n"; |
271 print COUT "#if $bracket\n\n"; | 315 print COUT "#if $bracket\n\n"; |
272 } | 316 } |
273 if ($command eq "no") | 317 if ($command eq "no" || $command eq "review") |
274 { | 318 { |
319 $reason = "Function needs review to determine how to handle it" | |
320 if !defined ($reason) && $command eq "review"; | |
321 | |
275 if (!defined ($reason)) | 322 if (!defined ($reason)) |
276 { | 323 { |
277 print "WARNING: No reason given for `no' with function $fun\n"; | 324 print "WARNING: No reason given for `no' with function $fun\n"; |
278 $reason = ""; | 325 $reason = ""; |
279 } | 326 } |
307 $split_rettype); | 354 $split_rettype); |
308 if ($command eq "split") | 355 if ($command eq "split") |
309 { | 356 { |
310 ($split_struct, $reason) = split /\s+/, $reason, 2; | 357 ($split_struct, $reason) = split /\s+/, $reason, 2; |
311 } | 358 } |
359 elsif ($command eq "override") | |
360 { | |
361 my ($nrettype, $nfun, $nargs) = @$filesarr[2 .. 4]; | |
362 $reason = "$reason.\n NOTE: " if $reason; | |
363 $reason = "${reason}Prototype manually overridden. | |
364 Header file claims: | |
365 $rettype $fun($args) | |
366 Overridden with: | |
367 $nrettype $nfun($nargs) | |
368 Differences in return-type qualifiers, e.g. WINAPI, are not important. | |
369 "; | |
370 ($rettype, $fun, $args) = ($nrettype, $nfun, $nargs); | |
371 } | |
312 my $argno = 0; | 372 my $argno = 0; |
313 while ($args =~ /$arg_re/g) | 373 while ($args =~ /$argmatch_re/g) |
314 { | 374 { |
315 $argno++; | 375 $argno++; |
316 my ($argtype, $argname) = ($1, $2); | 376 my ($argtype, $argname) = ($1, $2); |
317 $argtype =~ s/\s*$//; | 377 $argtype =~ s/\s*$//; |
318 next if $argtype eq "void" || $argtype eq "VOID"; | 378 next if $argtype eq "void" || $argtype eq "VOID"; |
332 } | 392 } |
333 push @args, $argname; | 393 push @args, $argname; |
334 } | 394 } |
335 $rettype =~ s/\bSHSTDAPI_\((.*)\)/$1/; | 395 $rettype =~ s/\bSHSTDAPI_\((.*)\)/$1/; |
336 $rettype =~ s/\s*WIN\w*?API\s*//g; | 396 $rettype =~ s/\s*WIN\w*?API\s*//g; |
337 $rettype =~ s/\bAPIENTRY\b//; | 397 $rettype =~ s/\bAPIENTRY\b\s*//; |
338 $rettype =~ s/\bSHSTDAPI\b/HRESULT/; | 398 $rettype =~ s/\bSHSTDAPI\b/HRESULT/; |
399 $rettype =~ s/\bextern\b\s*//; | |
339 if ($rettype =~ /LPC?WSTR/) | 400 if ($rettype =~ /LPC?WSTR/) |
340 { | 401 { |
341 $split_rettype = 1; | 402 $split_rettype = 1; |
342 $rettype =~ s/\bLPWSTR\b/Extbyte */; | 403 $rettype =~ s/\bLPWSTR\b/Extbyte */; |
343 $rettype =~ s/\bLPCWSTR\b/const Extbyte */; | 404 $rettype =~ s/\bLPCWSTR\b/const Extbyte */; |