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