New console code based on Win32 windows.
[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
9 %formats =
10 (
11     "int"           => "%d",
12     "short int"     => "%d",
13     "char"          => "%c",
14     "unsigned char" => "%02x",
15     "unsigned short"=> "%04x",
16     "unsigned int"  => "%08x",
17     "void*"         => "%p",
18     "time_t"        => "%ld",
19     "handle_t"      => "%d",
20     "atom_t"        => "%04x",
21     "user_handle_t" => "%08x",
22     "rectangle_t"   => "&dump_rectangle",
23 );
24
25 my @requests = ();
26 my %replies = ();
27
28 my @trace_lines = ();
29
30 # Get the server protocol version
31 my $protocol = &GET_PROTOCOL_VERSION;
32
33 ### Create server_protocol.h and print header
34
35 open SERVER_PROT, ">include/wine/server_protocol.h" or die "Cannot create include/wine/server_protocol.h";
36 print SERVER_PROT "/*\n * Wine server protocol definitions\n *\n";
37 print SERVER_PROT " * This file is automatically generated; DO NO EDIT!\n";
38 print SERVER_PROT " * Edit server/protocol.def instead and re-run tools/make_requests\n";
39 print SERVER_PROT " */\n\n";
40 print SERVER_PROT "#ifndef __WINE_WINE_SERVER_PROTOCOL_H\n";
41 print SERVER_PROT "#define __WINE_WINE_SERVER_PROTOCOL_H\n";
42
43 ### Parse requests to find request/reply structure definitions
44
45 &PARSE_REQUESTS;
46
47 ### Build the request list
48
49 print SERVER_PROT "\n\nenum request\n{\n";
50 foreach $req (@requests) { print SERVER_PROT "    REQ_$req,\n"; }
51 print SERVER_PROT "    REQ_NB_REQUESTS\n};\n\n";
52 print SERVER_PROT "union generic_request\n{\n";
53 print SERVER_PROT "    struct request_max_size max_size;\n";
54 print SERVER_PROT "    struct request_header header;\n";
55 foreach $req (@requests) { print SERVER_PROT "    struct ${req}_request $req;\n"; }
56 print SERVER_PROT "};\n\n";
57 printf SERVER_PROT "#define SERVER_PROTOCOL_VERSION %d\n\n", $protocol + 1;
58 print SERVER_PROT "#endif /* __WINE_WINE_SERVER_PROTOCOL_H */\n";
59 close SERVER_PROT;
60
61 ### Output the dumping function tables
62
63 push @trace_lines, "static const dump_func req_dumpers[REQ_NB_REQUESTS] = {\n";
64 foreach $req (@requests)
65 {
66     push @trace_lines, "    (dump_func)dump_${req}_request,\n";
67 }
68 push @trace_lines, "};\n\n";
69
70 push @trace_lines, "static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {\n";
71 foreach $req (@requests)
72 {
73     push @trace_lines, "    (dump_func)", $replies{$req} ? "dump_${req}_reply,\n" : "0,\n";
74 }
75 push @trace_lines, "};\n\n";
76
77 push @trace_lines, "static const char * const req_names[REQ_NB_REQUESTS] = {\n";
78 foreach $req (@requests)
79 {
80     push @trace_lines, "    \"$req\",\n";
81 }
82 push @trace_lines, "};\n";
83
84 REPLACE_IN_FILE( "server/trace.c", @trace_lines );
85
86 ### Output the request handlers list
87
88 my @request_lines = ();
89
90 foreach $req (@requests) { push @request_lines, "DECL_HANDLER($req);\n"; }
91 push @request_lines, "\n#ifdef WANT_REQUEST_HANDLERS\n\n";
92 push @request_lines, "typedef void (*req_handler)( void *req );\n";
93 push @request_lines, "static const req_handler req_handlers[REQ_NB_REQUESTS] =\n{\n";
94 foreach $req (@requests)
95 {
96     push @request_lines, "    (req_handler)req_$req,\n";
97 }
98 push @request_lines, "};\n#endif  /* WANT_REQUEST_HANDLERS */\n";
99
100 REPLACE_IN_FILE( "server/request.h", @request_lines );
101
102 ### Parse the request definitions
103
104 sub PARSE_REQUESTS
105 {
106     # states: 0 = header 1 = declarations 2 = inside @REQ 3 = inside @REPLY
107     my $state = 0;
108     my $name = "";
109     my @in_struct = ();
110     my @out_struct = ();
111
112     open(PROTOCOL,"server/protocol.def") or die "Can't open server/protocol.def";
113
114     while (<PROTOCOL>)
115     {
116         my ($type, $var);
117         # strip comments
118         s!/\*.*\*/!!g;
119         # strip white space at end of line
120         s/\s+$//;
121
122         if (/^\@HEADER/)
123         {
124             die "Misplaced \@HEADER" unless $state == 0;
125             $state++;
126             next;
127         }
128
129         # ignore everything while in state 0
130         next if $state == 0;
131
132         if (/^\@REQ\(\s*(\w+)\s*\)/)
133         {
134             $name = $1;
135             die "Misplaced \@REQ" unless $state == 1;
136             # start a new request
137             @in_struct = ();
138             @out_struct = ();
139             print SERVER_PROT "struct ${name}_request\n{\n";
140             print SERVER_PROT "    struct request_header __header;\n";
141             $state++;
142             next;
143         }
144
145         if (/^\@REPLY/)
146         {
147             die "Misplaced \@REPLY" unless $state == 2;
148             $state++;
149             next;
150         }
151
152         if (/^\@END/)
153         {
154             die "Misplaced \@END" unless ($state == 2 || $state == 3);
155             print SERVER_PROT "};\n";
156
157             # got a complete request
158             push @requests, $name;
159             &DO_DUMP_FUNC( $name, "request", @in_struct);
160             if ($#out_struct >= 0)
161             {
162                 $replies{$name} = 1;
163                 &DO_DUMP_FUNC( $name, "reply", @out_struct);
164             }
165             $state = 1;
166             next;
167         }
168
169         if ($state != 1)
170         {
171             # skip empty lines (but keep them in output file)
172             if (/^$/)
173             {
174                 print SERVER_PROT "\n";
175                 next;
176             }
177
178             if (/^\s*VARARG\((\w+),(\w+)\)/)
179             {
180                 $var = $1;
181                 $type = "&dump_varargs_" . $2;
182                 s!(VARARG\(.*\)\s*;)!/* $1 */!;
183             }
184             elsif (/^\s*(\w+\**(\s+\w+\**)*)\s+(\w+)(\[[1]\])?;/)
185             {
186                 $type = $1 . ($4 || "");
187                 $var = $3;
188                 die "Unrecognized type $type" unless (defined($formats{$type}) || $4);
189             }
190             else
191             {
192                 die "Unrecognized syntax $_";
193             }
194             if ($state == 2) { push @in_struct, $type, $var; }
195             if ($state == 3) { push @out_struct, $type, $var; }
196         }
197
198         # Pass it through into the output file
199         print SERVER_PROT $_ . "\n";
200     }
201     close PROTOCOL;
202 }
203
204 ### Generate a dumping function
205
206 sub DO_DUMP_FUNC
207 {
208     my $name = shift;
209     my $req = shift;
210     push @trace_lines, "static void dump_${name}_$req( const struct ${name}_request *req )\n{\n";
211     while ($#_ >= 0)
212     {
213         my $type = shift;
214         my $var = shift;
215         if (defined($formats{$type}))
216         {
217             if ($formats{$type} =~ /^&(.*)/)
218             {
219                 my $func = $1;
220                 push @trace_lines, "    fprintf( stderr, \" $var=\" );\n";
221                 if ($type =~ /[1]/) { push @trace_lines, "    $func( req, req->$var );\n"; }
222                 else { push @trace_lines, "    $func( req, &req->$var );\n"; }
223                 push @trace_lines, "    fprintf( stderr, \",\" );\n" if ($#_ > 0);
224             }
225             else
226             {
227                 push @trace_lines, "    fprintf( stderr, \" $var=$formats{$type}";
228                 push @trace_lines, "," if ($#_ > 0);
229                 push @trace_lines, "\", ";
230                 push @trace_lines, "req->$var );\n";
231             }
232         }
233         else  # must be some varargs format
234         {
235             if ($type =~ /^&(.*)/)
236             {
237                 my $func = $1;
238                 push @trace_lines, "    fprintf( stderr, \" $var=\" );\n";
239                 push @trace_lines, "    cur_pos += $func( req );\n";
240                 push @trace_lines, "    fputc( ',', stderr );\n" if ($#_ > 0);
241             }
242             else
243             {
244                 push @trace_lines, "    fprintf( stderr, \" $var=\" );\n";
245                 push @trace_lines, "    dump_varargs_${name}_${req}( req );\n";
246             }
247         }
248     }
249     push @trace_lines, "}\n\n";
250 }
251
252 ### Retrieve the server protocol version from the existing server_protocol.h file
253
254 sub GET_PROTOCOL_VERSION
255 {
256     my $protocol = 0;
257     open SERVER_PROT, "include/wine/server_protocol.h" or return 0;
258     while (<SERVER_PROT>)
259     {
260         if (/^\#define SERVER_PROTOCOL_VERSION (\d+)/) { $protocol = $1; last; }
261     }
262     close SERVER_PROT;
263     return $protocol;
264 }
265
266 ### Replace the contents of a file between ### make_requests ### marks
267
268 sub REPLACE_IN_FILE
269 {
270     my $name = shift;
271     my @data = @_;
272     my @lines = ();
273     open(FILE,$name) or die "Can't open $name";
274     while (<FILE>)
275     {
276         push @lines, $_;
277         last if /\#\#\# make_requests begin \#\#\#/;
278     }
279     push @lines, "\n", @data;
280     while (<FILE>)
281     {
282         if (/\#\#\# make_requests end \#\#\#/) { push @lines, "\n", $_; last; }
283     }
284     push @lines, <FILE>;
285     open(FILE,">$name") or die "Can't modify $name";
286     print FILE @lines;
287     close(FILE);
288 }