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