genprotocol.pl 4.2 KB
Newer Older
1
#!/usr/bin/env perl
2 3 4
#
# Generate code for an XDR protocol, optionally applying
# fixups to the glibc rpcgen code so that it compiles
5 6 7 8 9 10 11
# with warnings turned on.
#
# This code is evil.  Arguably better would be just to compile
# without -Werror.  Update: The IXDR_PUT_LONG replacements are
# actually fixes for 64 bit, so this file is necessary.  Arguably
# so is the type-punning fix.
#
E
Eric Blake 已提交
12
# Copyright (C) 2007, 2011-2013 Red Hat, Inc.
13
#
E
Eric Blake 已提交
14 15 16 17 18 19 20 21 22 23 24 25 26
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library.  If not, see
# <http://www.gnu.org/licenses/>.
27 28 29 30 31 32 33 34
#
# Richard Jones <rjones@redhat.com>

use strict;

my $in_function = 0;
my @function = ();

35 36 37 38 39 40 41
my $rpcgen = shift;
my $mode = shift;
my $xdrdef = shift;
my $target = shift;

unlink $target;

42 43 44 45
if ($rpcgen =~ /portable-rpcgen/) {
    $rpcgen = "$rpcgen -o -";
}
open RPCGEN, "-|", "$rpcgen $mode $xdrdef"
46 47 48 49
    or die "cannot run $rpcgen $mode $xdrdef: $!";
open TARGET, ">$target"
    or die "cannot create $target: $!";

50
my $fixup = $^O eq "linux" || $^O eq "cygwin" || $^O eq "gnukfreebsd" || $^O eq "freebsd" || $^O eq "darwin";
51 52 53 54 55 56 57 58 59

if ($mode eq "-c") {
    print TARGET "#include <config.h>\n";
}

while (<RPCGEN>) {
    # We only want to fixup the GLibc rpcgen output
    # So just print data unchanged, if non-Linux
    unless ($fixup) {
60 61
        print TARGET;
        next;
62 63
    }

64
    if (m/^{/) {
65 66 67
        $in_function = 1;
        print TARGET;
        next;
68 69
    }

70 71
    s/\t/        /g;

72 73 74
    # Fix VPATH builds
    s,#include ".*/([^/]+)protocol\.h",#include "${1}protocol.h",;

75 76 77 78 79
    # Portability for Solaris RPC
    s/u_quad_t/uint64_t/g;
    s/quad_t/int64_t/g;
    s/xdr_u_quad_t/xdr_uint64_t/g;
    s/xdr_quad_t/xdr_int64_t/g;
80
    s/(?<!IXDR_GET_INT32 )IXDR_GET_LONG/IXDR_GET_INT32/g;
81

82
    if (m/^}/) {
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
        $in_function = 0;

        # Note: The body of the function is in @function.

        # Remove decl of buf, if buf isn't used in the function.
        my @uses = grep /[^.>]\bbuf\b/, @function;
        @function = grep !/[^.>]\bbuf\b/, @function if @uses == 1;

        # Remove decl of i, if i isn't used in the function.
        @uses = grep /[^.>]\bi\b/, @function;
        @function = grep !/[^.>]\bi\b/, @function if @uses == 1;

        # (char **)&objp->... gives:
        # warning: dereferencing type-punned pointer will break
        #   strict-aliasing rules
        # so rewrite it.
        my %uses = ();
        my $i = 0;
        foreach (@function) {
            $uses{$1} = $i++ if m/\(char \*\*\)\&(objp->[a-z_.]+_val)/i;
        }
        if (keys %uses >= 1) {
            my $i = 1;

            foreach (keys %uses) {
                $i = $uses{$_};
                unshift @function,
                ("        char **objp_cpp$i = (char **) (void *) &$_;\n");
                $i++;
            }
            @function =
                map { s{\(char \*\*\)\&(objp->[a-z_.]+_val)}
                       {objp_cpp$uses{$1}}gi; $_ } @function;
        }

        # The code uses 'IXDR_PUT_{U_,}LONG' but it's wrong in two
        # ways: Firstly these functions are deprecated and don't
        # work on 64 bit platforms.  Secondly the return value should
        # be ignored.  Correct both these mistakes.
        @function =
            map { s/\bIXDR_PUT_((U_)?)LONG\b/(void)IXDR_PUT_$1INT32/; $_ }
            map { s/\bXDR_INLINE\b/(int32_t*)XDR_INLINE/; $_ }
            @function;

        print TARGET (join ("", @function));
        @function = ();
129 130 131
    }

    unless ($in_function) {
132
        print TARGET;
133
    } else {
134
        push @function, $_;
135 136
    }
}
137 138 139 140 141 142 143 144

close TARGET
    or die "cannot save $target: $!";
close RPCGEN
    or die "cannot shutdown $rpcgen: $!";

chmod 0444, $target
    or die "cannot set $target readonly: $!";