File: proto-decode-msg.pl

package info (click to toggle)
mah-jong 1.8-1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 2,384 kB
  • ctags: 2,186
  • sloc: ansic: 26,312; perl: 393; makefile: 272; sh: 122
file content (185 lines) | stat: -rw-r--r-- 6,785 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# $Header: /home/jcb/newmj/RCS/proto-decode-msg.pl,v 11.6 2003/09/29 21:24:19 jcb Rel $
# proto-decode-msg.pl
# script to generate body of decode_[cp]msg function in protocol.c
# it is not defensively programmed!
# The code it generates *is* defensively programmed, of course.
# Well, somewhat.

#***************** COPYRIGHT STATEMENT **********************
#* This file is Copyright (c) 2000 by J. C. Bradfield.       *
#* Distribution and use is governed by the LICENCE file that *
#* accompanies this file.                                    *
#* The moral rights of the author are asserted.              *
#*                                                           *
#***************** DISCLAIMER OF WARRANTY ********************
#* This code is not warranted fit for any purpose. See the   *
#* LICENCE file for further information.                     *
#*                                                           *
#*************************************************************

# debugging
$debug = $ENV{'DEBUG'};

# are we doing cmsg or pmsg ?
if ( $ARGV[0] eq '-cmsg' ) {
  $L = 'C' ; $l = 'c';
  $msgtype = "Controller";
  $infile = "protocol.h";
} elsif ( $ARGV[0] eq '-pmsg' ) {
  $L = 'P' ; $l = 'p' ;
  $msgtype = "Player";
  $infile = "protocol.h";
} elsif ( $ARGV[0] eq '-mcmsg' ) {
  $L = 'MC' ; $l = 'mc' ;
  $msgtype = "MController";
  $infile = "mprotocol.h";
} elsif ( $ARGV[0] eq '-mpmsg' ) {
  $L = 'MP' ; $l = 'mp' ;
  $msgtype = "MPlayer";
  $infile = "mprotocol.h";
} else {
  die("No function argument");
}

open(STDIN,"<$infile") or die("No infile");

open(STDOUT,">dec_${l}msg.c");

# The code we're trying to generate looks like this:
# if ( strcmp(type,"PlayerPungs") == 0) {
#   CMsgPlayerPungsMsg *m;
#
#   m = (CMsgPlayerPungsMsg *)malloc(sizeof(CMsgPlayerPungsMsg));
#   if ( ! m ) { warn("malloc failed\n") ; return (CMsgMsg *)0; }
#
#   m->type = CMsgPlayerPungs;
#
#   if ( sscanf(s,"%d%n",&an_int,&n) == 0 ) { warn("protocol error\n"); return (CMsgMsg *)0; }
#   m->id = an_int;
#   s += n;
#
#  and so on and so on. Note that for (char *) args, we need to 
#  malloc the space.

# a function to print the first few lines, given the type.
sub firstchunk {
  my($type) = $_[0];
  my($atext) = '';

  if ( $alias ) {
    $atext = " || strcmp(type,\"${alias}\") == 0 ";
  }
  print 
"  if ( strcmp(type,\"${type}\") == 0 ${atext}) {
    ${L}Msg${type}Msg *m;

    m = (${L}Msg${type}Msg *)malloc(sizeof(${L}Msg${type}Msg));
    if ( ! m ) { warn(\"malloc failed\\n\") ; return (${L}MsgMsg *)0; }

    m->type = ${L}Msg${type};

";
}

while ( ! eof(STDIN) ) {
  while ( <STDIN> ) {
    chop;
    # look for the beginning of the structure definition
    next unless s/^.*struct _${L}Msg// ;
    s/Msg \{//;
    # it is an undocumented fact that certain common commands have
    # short aliases, for ease in debugging via telnet sessions.
    # these are implemented via a comment of the form /* alias c */
    # on the typedef line.
    $alias = undef;
    if ( s,\s*/\*\s+alias\s+(\S+).*$,, ) { $alias = $1; }
    last if ! $_ ; # got to the dummy type
    $type = $_ ;
    $_ = <STDIN> ; # skip the type
    &firstchunk($type) ; # print the first few lines
    # now deal with the components
    while ( <STDIN> ) {
      chop;
      s/;.*$// ; # junk all but type and name
      if ( s/^\s*int\s+// ) {
	print '    if ( sscanf(s,"%d%n",&an_int,&n) == 0 ) { warn("protocol error\n"); return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    m->$_ = an_int;\n";
	print "    s += n;\n";
	print "    while ( isspace(*s) ) s++;\n\n";
	next;
      }
      if ( s/^\s*bool\s+// ) {
	print '    if ( sscanf(s,"%d%n",&an_int,&n) == 0 ) { warn("protocol error\n"); return (' . $L . 'MsgMsg *)0; }', "\n";
        print '    if ( an_int < 0 || an_int > 1 ) { warn("protocol error\n") ; return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    m->$_ = an_int;\n";
	print "    s += n;\n";
	print "    while ( isspace(*s) ) s++;\n\n";
	next;
      }
      if ( s/^\s*PlayerOption\s+// ) {
	print '    if ( sscanf(s,"%31s%n",little_string,&n) ==0 ) { warn("protocol error\n"); return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    m->$_ = player_scan_PlayerOption(little_string);\n";
	print "    s += n;\n";
	print "    while ( isspace(*s) ) s++;\n\n";
	next;
      }
      if ( s/^\s*TileWind\s+// ) {
	print '    if ( sscanf(s,"%c%n",&a_char,&n) == 0 ) { warn("protocol error\n"); return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    m->$_ = letterwind(a_char);\n";
	print "    s += n;\n";
	print "    while ( isspace(*s) ) s++;\n\n";
	next;
      }
      if ( s/^\s*Tile\s+// ) {
	print '    if ( sscanf(s,"%2s%n",little_string,&n) == 0 ) { warn("protocol error\n"); return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    m->$_ = tile_decode(little_string);\n";
	print "    if ( m->$_ == ErrorTile ) { warn(\"protocol error\\n\"); return (${L}MsgMsg *)0; }\n";
	print "    s += n;\n";
	print "    while ( isspace(*s) ) s++;\n\n";
	next;
      }
      if ( s/^\s*word(\d+)\s+// ) {
	$wordlen = $1;
	print '    if ( sscanf(s,"%',$wordlen,'s%n",little_string,&n) == 0 ) { warn("protocol error\n");  return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    strmcpy(m->$_,little_string,$wordlen);\n";
	print "    s += n;\n";
	print "    while ( isspace(*s) ) s++;\n\n";
	next;
      }
      if ( s/^\s*ChowPosition\s+// ) {
	# the 31 field width is for safety. This string should always
	# be lower, middle or upper!
	# Argh. This code does not defend against protocol errors.
	# FIXME
	print '    if ( sscanf(s,"%31s%n",little_string,&n) == 0 ) { warn("protocol error\n"); return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    m->$_ = string_cpos(little_string);\n";
	print "    s += n;\n";
	print "    while ( isspace(*s) ) s++;\n\n";
	next;
      }
      if ( s/^\s*char\s+\*\s*// ) {
	# we are allowed to assume this is the last field
	print "    if ( strlen(s) == 0 ) m->$_ = (char *)0;\n";
	print "    else {\n";
	print "      m->$_ = (char *)malloc(strlen(s)+1);\n";
	print "      if ( ! m->$_ ) { warn(\"malloc failed\\n\"); return (${L}MsgMsg *)0; }\n";
	# we now need to do a little backslash unescaping.
        # At this level of protocol, all we do is say: if arg starts
	# with \, remove it - any initial backslash must be there
	# to protect the next character
	print "      strcpy(m->$_,s+(s[0] == '\\\\'));\n";
	print "    }\n";
	next;
      }
      if ( s/^\s*GameOptionEntry\s+// ) {
	print '    if ( (goe = protocol_scan_GameOptionEntry(s)) == 0 ) { warn("protocol error\n"); return (' . $L . 'MsgMsg *)0; }', "\n";
	print "    memcpy(&m->$_,goe,sizeof(GameOptionEntry));\n";
	next;
      }
      last if  s/^\}// ; # the end
      print STDERR "I hope this is a comment: $_\n" if $debug;
    }
    print "    return (${L}MsgMsg *) m;\n";
    print "  }\n";
  }
}