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 */;