| #! /usr/bin/perl -w |
| # |
| # Build the server/trace.c and include/server/request.h files |
| # from the contents of include/server.h. |
| # |
| # Copyright (C) 1998 Alexandre Julliard |
| # |
| |
| %formats = |
| ( |
| "int" => "%d", |
| "char" => "%c", |
| "char[0]" => "\\\"%.*s\\\"", |
| "unsigned int" => "%08x", |
| "void*" => "%p", |
| "time_t" => "%ld" |
| ); |
| |
| my @requests = (); |
| my %replies = (); |
| |
| open(SERVER,"include/server.h") or die "Can't open include/server.h"; |
| open(TRACE,">server/trace.c") or die "Can't create server/trace.c"; |
| open(REQUESTS,">include/server/request.h") or die "Can't create include/server/request.h"; |
| |
| ### Generate the header |
| |
| print TRACE <<EOF; |
| /* File generated automatically by $0; DO NOT EDIT!! */ |
| |
| #include <stdio.h> |
| #include <sys/types.h> |
| #include <sys/uio.h> |
| #include "server.h" |
| #include "server/thread.h" |
| EOF |
| |
| ### Parse server.h to find request/reply structure definitions |
| |
| while (<SERVER>) |
| { |
| if (/^struct +(\w+)_request/) { &DO_REQUEST($1); } |
| if (/^struct +(\w+)_reply/) { &DO_REPLY($1); } |
| } |
| |
| ### Output the dumping function tables |
| |
| print TRACE<<EOF; |
| |
| struct dumper |
| { |
| int (*dump_req)( void *data, int len ); |
| void (*dump_reply)( void *data ); |
| }; |
| |
| static const struct dumper dumpers[REQ_NB_REQUESTS] = |
| { |
| EOF |
| |
| foreach $req (@requests) |
| { |
| $request = $req . "_request"; |
| $reply = $replies{$req} ? "dump_${req}_reply" : "0"; |
| print TRACE " { (int(*)(void *,int))dump_$request,\n"; |
| print TRACE " (void(*)())$reply },\n"; |
| } |
| |
| print TRACE <<EOF; |
| }; |
| |
| static const char * const req_names[REQ_NB_REQUESTS] = |
| { |
| EOF |
| foreach $req (@requests) |
| { |
| print TRACE " \"$req\",\n"; |
| } |
| |
| ### Output the tracing functions |
| |
| print TRACE <<EOF; |
| }; |
| |
| void trace_request( enum request req, void *data, int len, int fd ) |
| { |
| int size; |
| current->last_req = req; |
| printf( "%08x: %s(", (unsigned int)current, req_names[req] ); |
| size = dumpers[req].dump_req( data, len ); |
| if ((len -= size) > 0) |
| { |
| unsigned char *ptr = (unsigned char *)data + size; |
| while (len--) printf( ", %02x", *ptr++ ); |
| } |
| if (fd != -1) printf( " ) fd=%d\\n", fd ); |
| else printf( " )\\n" ); |
| } |
| |
| void trace_timeout(void) |
| { |
| printf( "%08x: *timeout*\\n", (unsigned int)current ); |
| } |
| |
| void trace_kill( int exit_code ) |
| { |
| printf( "%08x: *killed* exit_code=%d\\n", |
| (unsigned int)current, exit_code ); |
| } |
| |
| void trace_reply( struct thread *thread, int type, int pass_fd, |
| struct iovec *vec, int veclen ) |
| { |
| if (!thread) return; |
| printf( "%08x: %s() = %d", |
| (unsigned int)thread, req_names[thread->last_req], type ); |
| if (veclen) |
| { |
| printf( " {" ); |
| if (dumpers[thread->last_req].dump_reply) |
| { |
| dumpers[thread->last_req].dump_reply( vec->iov_base ); |
| vec++; |
| veclen--; |
| } |
| for (; veclen; veclen--, vec++) |
| { |
| unsigned char *ptr = vec->iov_base; |
| int len = vec->iov_len; |
| while (len--) printf( ", %02x", *ptr++ ); |
| } |
| printf( " }" ); |
| } |
| if (pass_fd != -1) printf( " fd=%d\\n", pass_fd ); |
| else printf( "\\n" ); |
| } |
| EOF |
| |
| ### Output the requests list |
| |
| print REQUESTS <<EOF; |
| /* File generated automatically by $0; DO NOT EDIT!! */ |
| |
| #ifndef __WINE_SERVER_REQUEST_H |
| #define __WINE_SERVER_REQUEST_H |
| |
| enum request |
| { |
| EOF |
| |
| foreach $req (@requests) |
| { |
| print REQUESTS " REQ_\U$req,\n"; |
| } |
| |
| print REQUESTS <<EOF; |
| REQ_NB_REQUESTS |
| }; |
| |
| #ifdef WANT_REQUEST_HANDLERS |
| |
| #define DECL_HANDLER(name) \\ |
| static void req_##name( struct name##_request *req, void *data, int len, int fd ) |
| |
| EOF |
| |
| foreach $req (@requests) { print REQUESTS "DECL_HANDLER($req);\n"; } |
| |
| print REQUESTS <<EOF; |
| |
| static const struct handler { |
| void (*handler)(); |
| unsigned int min_size; |
| } req_handlers[REQ_NB_REQUESTS] = { |
| EOF |
| |
| foreach $req (@requests) |
| { |
| print REQUESTS " { (void(*)())req_$req, sizeof(struct ${req}_request) },\n"; |
| } |
| |
| print REQUESTS <<EOF; |
| }; |
| #endif /* WANT_REQUEST_HANDLERS */ |
| |
| #endif /* __WINE_SERVER_REQUEST_H */ |
| EOF |
| |
| ### Handle a request structure definition |
| |
| sub DO_REQUEST |
| { |
| my $name = shift; |
| my @struct = (); |
| while (<SERVER>) |
| { |
| last if /^};$/; |
| next if /^{$/; |
| s!/\*.*\*/!!g; |
| next if /^\s*$/; |
| / *(\w+\**( +\w+\**)*) +(\w+)(\[0\])?;/ or die "Unrecognized syntax $_"; |
| my $type = $1 . ($4 || ""); |
| my $var = $3; |
| die "Unrecognized type $type" unless defined($formats{$type}); |
| push @struct, $type, $var; |
| } |
| push @requests, $name; |
| &DO_DUMP_FUNC( $name . "_request",@struct); |
| } |
| |
| ### Handle a reply structure definition |
| |
| sub DO_REPLY |
| { |
| my $name = shift; |
| my @struct = (); |
| while (<SERVER>) |
| { |
| last if /^};$/; |
| next if /^{$/; |
| s!/\*.*\*/!!g; |
| next if /^\s*$/; |
| / *(\w+\**( +\w+\**)*) +(\w+);/ or die "Unrecognized syntax $_"; |
| my $type = $1; |
| my $var = $3; |
| die "Unrecognized type $type" unless defined($formats{$type}); |
| push @struct, $type, $var; |
| } |
| $replies{$name} = 1; |
| &DO_DUMP_FUNC( $name . "_reply" ,@struct); |
| } |
| |
| ### Generate a dumping function |
| |
| sub DO_DUMP_FUNC |
| { |
| my $vararg = 0; |
| my $name = shift; |
| print TRACE "\nstatic int dump_$name( struct $name *req, int len )\n{\n"; |
| while ($#_ >= 0) |
| { |
| my $type = shift; |
| my $var = shift; |
| print TRACE " printf( \" $var=$formats{$type}"; |
| print TRACE "," if ($#_ > 0); |
| print TRACE "\", "; |
| if ($type =~ s/\[0\]$//g) # vararg type? |
| { |
| $vararg = 1; |
| print TRACE "len - (int)sizeof(*req), ($type *)(req+1) );\n"; |
| } |
| else |
| { |
| print TRACE "req->$var );\n"; |
| } |
| } |
| print TRACE " return ", $vararg ? "len" : "(int)sizeof(*req)", ";\n}\n"; |
| } |