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