1# $Header: /home/jcb/MahJong/newmj/RCS/proto-encode-msg.pl,v 12.1 2012/02/01 15:29:24 jcb Rel $
2# proto-encode-msg.pl
3# generate the protocol conversion switch for c/pmsgs
4# Also, generate in cmsg_union.h a definition of a
5# massive union type.
6# Also, in cmsg_size.c, a function to return the size of a given
7# type of cmsg. If the size is -n, that indicates that the
8# last field (last sizeof(char*) bytes) is a char *.
9
10#***************** COPYRIGHT STATEMENT **********************
11#* This file is Copyright (c) 2000 by J. C. Bradfield.       *
12#* Distribution and use is governed by the LICENCE file that *
13#* accompanies this file.                                    *
14#* The moral rights of the author are asserted.              *
15#*                                                           *
16#***************** DISCLAIMER OF WARRANTY ********************
17#* This code is not warranted fit for any purpose. See the   *
18#* LICENCE file for further information.                     *
19#*                                                           *
20#*************************************************************
21
22# debugging
23$debug = $ENV{'DEBUG'};
24
25# are we doing cmsg or pmsg ?
26if ( $ARGV[0] eq '-cmsg' ) {
27  $L = 'C' ; $l = 'c';
28  $msgtype = "Controller";
29  $infile = "protocol.h";
30} elsif ( $ARGV[0] eq '-pmsg' ) {
31  $L = 'P' ; $l = 'p' ;
32  $msgtype = "Player";
33  $infile = "protocol.h";
34} elsif ( $ARGV[0] eq '-mcmsg' ) {
35  $L = 'MC' ; $l = 'mc' ;
36  $msgtype = "MController";
37  $infile = "mprotocol.h";
38} elsif ( $ARGV[0] eq '-mpmsg' ) {
39  $L = 'MP' ; $l = 'mp' ;
40  $msgtype = "MPlayer";
41  $infile = "mprotocol.h";
42} else {
43  die("No function argument");
44}
45
46open(IN,"<$infile") or die("No infile");
47
48open(STDOUT,">enc_${l}msg.c");
49open(UNION,">${l}msg_union.h");
50open(SIZE,">${l}msg_size.c");
51
52print UNION
53"typedef union _${L}MsgUnion {
54  /* Note that this type field relies on the fact that all
55     messages have type as their first field */\n";
56print UNION $msgtype, "MsgType type;\n";
57
58print SIZE
59"static int ${l}msg_size[] = {\n";
60
61while ( ! eof(IN) ) {
62  while ( <IN> ) {
63    # unfortunately, we need to catch the enum values
64    if ( /^\s*${L}Msg(\S+)\s*=\s*(\d+)/ ) {
65      $enums[$2] = $1;
66    }
67    next if ! /struct _${L}Msg/;
68    chop;
69    s/^.*${L}Msg//; s/Msg\s*\{// ;
70    s,\s*/\*.*$,, ; # strip comment
71    $type = $_ ;
72    if ( ! $type ) { # reached the dummy type
73      $doneall = 1;
74      last;
75    }
76    print "  case ${L}Msg$type: \n";
77    print "    { ${L}Msg${type}Msg *m UNUSED = (${L}Msg${type}Msg *) msg;\n";
78    $format = "$type";
79    # special hack for the Comment message
80    if ( $type eq 'Comment' ) { $format = "#"; }
81    $args = '';
82    $dofinish = 1;
83    $_ = <IN> ; # skip type
84    while ( <IN> ) {
85      chop;
86      if ( s/^\s*int\s+// ) {
87	$format .= " %d";
88	s/;.*//;
89	$args .= ", m->$_";
90      } elsif ( s/^\s*bool\s+// ) {
91	$format .= " %d";
92	s/;.*//;
93	print "    badfield = 0;\n";
94	print "    if ( m->$_ < 0 || m->$_ > 1 ) { warn(\"bad boolean in message, assuming TRUE\"); badfield = 1 ; };\n";
95	$args .= ", (badfield ? 1 : m->$_)";
96      } elsif ( s/^\s*char \*// ) {
97	s/;.*//;
98	# if the argument happens to start with a space or backslash, then
99	# we need to escape it with a backslash
100	$format .= " %s%s";
101	# if the argument is null, don't pass it to printf,
102	# but pass the empty string instead
103	$args .= ",(m->$_ && (m->$_\[0] == ' ' || m->$_\[0] == '\\\\')) ? \"\\\\\" : \"\", m->$_ ? m->$_ : \"\" ";
104	# and flag this type:
105	$charstar{$type} = $_; # see below ...
106      } elsif ( s/^\s*word\d+\s+// ) {
107	$format .= " %s";
108	s/;.*//;
109	$args .= ", m->$_ ";
110      } elsif ( s/^\s*TileWind\s+// ) {
111	$format .= " %c";
112	s/;.*//;
113	$args .= ", windletter(m->$_)";
114      } elsif ( s/^\s*PlayerOption\s+// ) {
115	$format .= " %s";
116	s/;.*//;
117	$args .= ", player_print_PlayerOption(m->$_)";
118      } elsif ( s/^\s*Tile\s+// ) {
119	$format .= " %s";
120	s/;.*//;
121	$args .= ", tile_code(m->$_)";
122      } elsif ( s/^\s*ChowPosition\s+// ) {
123	$format .= " %s";
124	s/;.*//;
125	$args .= ", cpos_string(m->$_)";
126      } elsif ( s/^\s*GameOptionEntry\s+// ) {
127	$format .= " %s";
128	s/;.*//;
129	$args .= ", protocol_print_GameOptionEntry(&m->$_)";
130      } elsif ( /^\}/ ) { last ; }
131      else { print STDERR "hope this is a comment: $_\n" if $debug; }
132    }
133    next if ! $dofinish;
134    $format .= '\r\n';
135    print "      while (1) {\n";
136    print "        int size = snprintf(buf,buf_size,\"$format\"$args);\n";
137    print "        if ((size >= 0)&&(size < (int)buf_size))\n";
138    print "          break;\n";
139    print "        buf_size = (size >= 0)?((size_t)size+1):(buf_size > 0)?(buf_size*2):1024;\n";
140    print "        buf = realloc(buf, buf_size);\n";
141    print "        if (!buf) {\n";
142    print "          perror(\"encode_" . $l . "msg\");\n";
143    print "          exit(-1);\n";
144    print "        }\n";
145    print "      }\n";
146    print "    }\n";
147    print "    break;\n";
148  }
149  last if $doneall;
150}
151
152for ( $i = 0; $i <= $#enums; $i++ ) {
153  $t = $enums[$i];
154  if ( $t ) {
155    $s = $t;
156    $s =~ tr/A-Z/a-z/;
157    print UNION "${L}Msg${t}Msg $s;\n";
158  }
159  if ( defined($charstar{$t}) ) { $neg = '-' ; } else { $neg = '' ; }
160  print SIZE +($t ? "${neg}(int)sizeof(${L}Msg${t}Msg)" : 0), ",\n";
161}
162
163print UNION "} ${L}MsgUnion;\n";
164print SIZE
165"};
166
167int ${l}msg_size_of(",$msgtype,"MsgType t) { return ${l}msg_size[t]; }\n\n";
168
169# While we're at it, we'll also generate functions to do
170# a deep copy (malloc'ing all space), and to deep free
171# the structures.
172
173print SIZE
174  "${L}MsgMsg *${l}msg_deepcopy(${L}MsgMsg *m) {
175  ${L}MsgMsg *n;
176  int size;
177  char *mc,*nc;
178
179  size = ${l}msg_size_of(m->type);
180  if ( size < 0 ) size *= -1;
181  n = (${L}MsgMsg *)malloc(size);
182  if ( ! n ) return n;
183
184  memcpy((void *)n,(const void *)m,size);
185  switch ( m->type ) {
186";
187
188foreach $k ( keys %charstar ) {
189  $c = $charstar{$k};
190  print SIZE
191"  case ${L}Msg$k:
192    mc = ((${L}Msg${k}Msg *)m)->$c;
193    if ( mc ) {
194      nc = (char *)malloc(strlen(mc)+1);
195      if ( ! nc ) return NULL;
196      strcpy(nc,mc);
197    } else {
198      nc = NULL;
199    }
200    ((${L}Msg${k}Msg *)n)->$c = nc;
201    break;
202";
203}
204
205print SIZE
206"  default:
207      ;
208  }
209  return n;
210}\n\n";
211
212print SIZE
213"void ${l}msg_deepfree(${L}MsgMsg *m) {
214  switch ( m->type ) {
215";
216
217foreach $k ( keys %charstar ) {
218  $c = $charstar{$k};
219  print SIZE
220"  case ${L}Msg$k:
221    if ( ((${L}Msg${k}Msg *)m)->$c )
222      free((void *)((${L}Msg${k}Msg *)m)->$c);
223    break;
224";
225}
226
227print SIZE
228"  default:
229      ;
230  }
231  free((void *)m);
232}\n\n";
233