wine.inf: Add hhctrl.ocx to the list of fake dlls.
[wine] / tools / make_requests
1 #! /usr/bin/perl -w
2 #
3 # Build the server/trace.c and server/request.h files
4 # from the contents of include/wine/server.h.
5 #
6 # Copyright (C) 1998 Alexandre Julliard
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 #
22 use strict;
23
24 my %formats =
25 (
26     "int"           => "%d",
27     "short int"     => "%d",
28     "char"          => "%c",
29     "unsigned char" => "%02x",
30     "unsigned short"=> "%04x",
31     "unsigned int"  => "%08x",
32     "void*"         => "%p",
33     "time_t"        => "%ld (long)",
34     "size_t"        => "%lu (unsigned long)",
35     "obj_handle_t"  => "%p",
36     "atom_t"        => "%04x",
37     "user_handle_t" => "%p",
38     "process_id_t"  => "%04x",
39     "thread_id_t"   => "%04x",
40     "abs_time_t"    => "&dump_abs_time",
41     "rectangle_t"   => "&dump_rectangle",
42     "char_info_t"   => "&dump_char_info",
43 );
44
45 my @requests = ();
46 my %replies = ();
47
48 my @trace_lines = ();
49
50
51
52 ### Generate a dumping function
53
54 sub DO_DUMP_FUNC($$@)
55 {
56     my $name = shift;
57     my $req = shift;
58     push @trace_lines, "static void dump_${name}_$req( const struct ${name}_$req *req )\n{\n";
59     while ($#_ >= 0)
60     {
61         my $type = shift;
62         my $var = shift;
63         if (defined($formats{$type}))
64         {
65             if ($formats{$type} =~ /^&(.*)/)
66             {
67                 my $func = $1;
68                 push @trace_lines, "    fprintf( stderr, \" $var=\" );\n";
69                 push @trace_lines, "    $func( &req->$var );\n";
70                 push @trace_lines, "    fprintf( stderr, \",\" );\n" if ($#_ > 0);
71             }
72             elsif ($formats{$type} =~ /^(%.*)\s+\((.*)\)/)
73             {
74                 my ($format, $cast) = ($1, $2);
75                 push @trace_lines, "    fprintf( stderr, \" $var=$format";
76                 push @trace_lines, "," if ($#_ > 0);
77                 push @trace_lines, "\", ($cast)req->$var );\n";
78             }
79             else
80             {
81                 push @trace_lines, "    fprintf( stderr, \" $var=$formats{$type}";
82                 push @trace_lines, "," if ($#_ > 0);
83                 push @trace_lines, "\", req->$var );\n";
84             }
85         }
86         else  # must be some varargs format
87         {
88             my $func = $type;
89             push @trace_lines, "    fprintf( stderr, \" $var=\" );\n";
90             push @trace_lines, "    $func;\n";
91             push @trace_lines, "    fputc( ',', stderr );\n" if ($#_ > 0);
92         }
93     }
94     push @trace_lines, "}\n\n";
95 }
96
97 ### Parse the request definitions
98
99 sub PARSE_REQUESTS()
100 {
101     # states: 0 = header 1 = declarations 2 = inside @REQ 3 = inside @REPLY
102     my $state = 0;
103     my $name = "";
104     my @in_struct = ();
105     my @out_struct = ();
106
107     open(PROTOCOL,"server/protocol.def") or die "Can't open server/protocol.def";
108
109     while (<PROTOCOL>)
110     {
111         my ($type, $var);
112         # strip comments
113         s!/\*.*\*/!!g;
114         # strip white space at end of line
115         s/\s+$//;
116
117         if (/^\@HEADER/)
118         {
119             die "Misplaced \@HEADER" unless $state == 0;
120             $state++;
121             next;
122         }
123
124         # ignore everything while in state 0
125         next if $state == 0;
126
127         if (/^\@REQ\(\s*(\w+)\s*\)/)
128         {
129             $name = $1;
130             die "Misplaced \@REQ" unless $state == 1;
131             # start a new request
132             @in_struct = ();
133             @out_struct = ();
134             print SERVER_PROT "struct ${name}_request\n{\n";
135             print SERVER_PROT "    struct request_header __header;\n";
136             $state++;
137             next;
138         }
139
140         if (/^\@REPLY/)
141         {
142             die "Misplaced \@REPLY" unless $state == 2;
143             print SERVER_PROT "};\n";
144             print SERVER_PROT "struct ${name}_reply\n{\n";
145             print SERVER_PROT "    struct reply_header __header;\n";
146             $state++;
147             next;
148         }
149
150         if (/^\@END/)
151         {
152             die "Misplaced \@END" unless ($state == 2 || $state == 3);
153             print SERVER_PROT "};\n";
154
155             if ($state == 2)  # build dummy reply struct
156             {
157                 print SERVER_PROT "struct ${name}_reply\n{\n";
158                 print SERVER_PROT "    struct reply_header __header;\n";
159                 print SERVER_PROT "};\n";
160             }
161
162             # got a complete request
163             push @requests, $name;
164             DO_DUMP_FUNC( $name, "request", @in_struct);
165             if ($#out_struct >= 0)
166             {
167                 $replies{$name} = 1;
168                 DO_DUMP_FUNC( $name, "reply", @out_struct);
169             }
170             $state = 1;
171             next;
172         }
173
174         if ($state != 1)
175         {
176             # skip empty lines (but keep them in output file)
177             if (/^$/)
178             {
179                 print SERVER_PROT "\n";
180                 next;
181             }
182
183             if (/^\s*VARARG\((\w+),(\w+),(\w+)\)/)
184             {
185                 $var = $1;
186                 $type = "dump_varargs_" . $2 . "( min(cur_size,req->" . $3 . ") )";
187                 s!(VARARG\(.*\)\s*;)!/* $1 */!;
188             }
189             elsif (/^\s*VARARG\((\w+),(\w+)\)/)
190             {
191                 $var = $1;
192                 $type = "dump_varargs_" . $2 . "( cur_size )";
193                 s!(VARARG\(.*\)\s*;)!/* $1 */!;
194             }
195             elsif (/^\s*(\w+\**(\s+\w+\**)*)\s+(\w+);/)
196             {
197                 $type = $1;
198                 $var = $3;
199                 die "Unrecognized type $type" unless defined($formats{$type});
200             }
201             else
202             {
203                 die "Unrecognized syntax $_";
204             }
205             if ($state == 2) { push @in_struct, $type, $var; }
206             if ($state == 3) { push @out_struct, $type, $var; }
207         }
208
209         # Pass it through into the output file
210         print SERVER_PROT $_ . "\n";
211     }
212     close PROTOCOL;
213 }
214
215 ### Retrieve the server protocol version from the existing server_protocol.h file
216
217 sub GET_PROTOCOL_VERSION()
218 {
219     my $protocol = 0;
220     open SERVER_PROT, "include/wine/server_protocol.h" or return 0;
221     while (<SERVER_PROT>)
222     {
223         if (/^\#define SERVER_PROTOCOL_VERSION (\d+)/) { $protocol = $1; last; }
224     }
225     close SERVER_PROT;
226     return $protocol;
227 }
228
229 ### Retrieve the list of status and errors used in the server
230
231 sub GET_ERROR_NAMES()
232 {
233     my %errors = ();
234     foreach my $f (glob "server/*.c")
235     {
236         open FILE, $f or die "Can't open $f";
237         while (<FILE>)
238         {
239             if (/set_error\s*\(\s*STATUS_(\w+)\s*\)/)
240             {
241                 $errors{$1} = "STATUS_$1";
242             }
243             elsif (/set_win32_error\s*\(\s*(\w+)\s*\)/)
244             {
245                 $errors{$1} = "0xc0010000 | $1";
246             }
247         }
248         close FILE;
249     }
250     return %errors;
251 }
252
253 ### Replace the contents of a file between ### make_requests ### marks
254
255 sub REPLACE_IN_FILE($@)
256 {
257     my $name = shift;
258     my @data = @_;
259     my @lines = ();
260     open(FILE,$name) or die "Can't open $name";
261     while (<FILE>)
262     {
263         push @lines, $_;
264         last if /\#\#\# make_requests begin \#\#\#/;
265     }
266     push @lines, "\n", @data;
267     while (<FILE>)
268     {
269         if (/\#\#\# make_requests end \#\#\#/) { push @lines, "\n", $_; last; }
270     }
271     push @lines, <FILE>;
272     open(FILE,">$name") or die "Can't modify $name";
273     print FILE @lines;
274     close(FILE);
275 }
276
277 ### Main
278
279 # Get the server protocol version
280 my $protocol = GET_PROTOCOL_VERSION();
281
282 my %errors = GET_ERROR_NAMES();
283
284 ### Create server_protocol.h and print header
285
286 open SERVER_PROT, ">include/wine/server_protocol.h" or die "Cannot create include/wine/server_protocol.h";
287 print SERVER_PROT "/*\n * Wine server protocol definitions\n *\n";
288 print SERVER_PROT " * This file is automatically generated; DO NO EDIT!\n";
289 print SERVER_PROT " * Edit server/protocol.def instead and re-run tools/make_requests\n";
290 print SERVER_PROT " */\n\n";
291 print SERVER_PROT "#ifndef __WINE_WINE_SERVER_PROTOCOL_H\n";
292 print SERVER_PROT "#define __WINE_WINE_SERVER_PROTOCOL_H\n";
293
294 ### Parse requests to find request/reply structure definitions
295
296 PARSE_REQUESTS();
297
298 ### Build the request list and structures
299
300 print SERVER_PROT "\n\nenum request\n{\n";
301 foreach my $req (@requests) { print SERVER_PROT "    REQ_$req,\n"; }
302 print SERVER_PROT "    REQ_NB_REQUESTS\n};\n\n";
303
304 print SERVER_PROT "union generic_request\n{\n";
305 print SERVER_PROT "    struct request_max_size max_size;\n";
306 print SERVER_PROT "    struct request_header request_header;\n";
307 foreach my $req (@requests) { print SERVER_PROT "    struct ${req}_request ${req}_request;\n"; }
308 print SERVER_PROT "};\n";
309
310 print SERVER_PROT "union generic_reply\n{\n";
311 print SERVER_PROT "    struct request_max_size max_size;\n";
312 print SERVER_PROT "    struct reply_header reply_header;\n";
313 foreach my $req (@requests) { print SERVER_PROT "    struct ${req}_reply ${req}_reply;\n"; }
314 print SERVER_PROT "};\n\n";
315
316 printf SERVER_PROT "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol + 1;
317 print SERVER_PROT "#endif /* __WINE_WINE_SERVER_PROTOCOL_H */\n";
318 close SERVER_PROT;
319
320 ### Output the dumping function tables
321
322 push @trace_lines, "static const dump_func req_dumpers[REQ_NB_REQUESTS] = {\n";
323 foreach my $req (@requests)
324 {
325     push @trace_lines, "    (dump_func)dump_${req}_request,\n";
326 }
327 push @trace_lines, "};\n\n";
328
329 push @trace_lines, "static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {\n";
330 foreach my $req (@requests)
331 {
332     push @trace_lines, "    (dump_func)", $replies{$req} ? "dump_${req}_reply,\n" : "0,\n";
333 }
334 push @trace_lines, "};\n\n";
335
336 push @trace_lines, "static const char * const req_names[REQ_NB_REQUESTS] = {\n";
337 foreach my $req (@requests)
338 {
339     push @trace_lines, "    \"$req\",\n";
340 }
341 push @trace_lines, "};\n\n";
342
343 push @trace_lines, "static const struct\n{\n";
344 push @trace_lines, "    const char  *name;\n";
345 push @trace_lines, "    unsigned int value;\n";
346 push @trace_lines, "} status_names[] =\n{\n";
347
348 foreach my $err (sort keys %errors)
349 {
350     push @trace_lines, sprintf("    { %-30s %s },\n", "\"$err\",", $errors{$err});
351 }
352 push @trace_lines, "    { NULL, 0 }\n";
353 push @trace_lines, "};\n";
354
355 REPLACE_IN_FILE( "server/trace.c", @trace_lines );
356
357 ### Output the request handlers list
358
359 my @request_lines = ();
360
361 foreach my $req (@requests) { push @request_lines, "DECL_HANDLER($req);\n"; }
362 push @request_lines, "\n#ifdef WANT_REQUEST_HANDLERS\n\n";
363 push @request_lines, "typedef void (*req_handler)( const void *req, void *reply );\n";
364 push @request_lines, "static const req_handler req_handlers[REQ_NB_REQUESTS] =\n{\n";
365 foreach my $req (@requests)
366 {
367     push @request_lines, "    (req_handler)req_$req,\n";
368 }
369 push @request_lines, "};\n#endif  /* WANT_REQUEST_HANDLERS */\n";
370
371 REPLACE_IN_FILE( "server/request.h", @request_lines );