Stop sharing requirement_unit_state_ereq().
[freeciv.git] / common / generate_packets.py
blob15e9c5f5bae0cf655e91f8836c40225a60cc18e7
1 #!/usr/bin/env python
4 # Freeciv - Copyright (C) 2003 - Raimar Falke
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2, or (at your option)
8 # any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
16 ### The following parameters change the amount of output.
18 # generate_stats will generate a large amount of statistics how many
19 # info packets got discarded and how often a field is transmitted. You
20 # have to call delta_stats_report to get these.
21 generate_stats=0
23 # generate_logs will generate log calls to debug the delta code.
24 generate_logs=1
25 use_log_macro="log_packet_detailed"
26 generate_variant_logs=1
28 ### The following parameters CHANGE the protocol. You have been warned.
29 fold_bool_into_header=1
31 ################# END OF PARAMETERS ####################
33 # This program runs under python 1.5 and 2.2 and hopefully every
34 # version in between. Please leave it so. In particular use the string
35 # module and not the function of the string type.
37 import re, string, os, sys
39 lazy_overwrite=0
41 def verbose(s):
42 if "-v" in sys.argv:
43 print(s)
45 def prefix(prefix,str):
46 lines=str.split("\n")
47 lines=map(lambda x,prefix=prefix: prefix+x,lines)
48 return "\n".join(lines)
50 def write_disclaimer(f):
51 f.write('''
52 /****************************************************************************
53 * THIS FILE WAS GENERATED *
54 * Script: common/generate_packets.py *
55 * Input: common/networking/packets.def *
56 * DO NOT CHANGE THIS FILE *
57 ****************************************************************************/
59 ''')
61 def fc_open(name):
62 verbose("writing %s"%name)
63 f=open(name,"w")
64 write_disclaimer(f)
65 return f
67 def get_choices(all):
68 def helper(helper,all, index, so_far):
69 if index>=len(all):
70 return [so_far]
71 t0=so_far[:]
72 t1=so_far[:]
73 t1.append(list(all)[index])
74 return helper(helper,all,index+1,t1)+helper(helper,all,index+1,t0)
76 result=helper(helper,all,0,[])
77 assert len(result)==2**len(all)
78 return result
80 def without(all,part):
81 result=[]
82 for i in all:
83 if i not in part:
84 result.append(i)
85 return result
87 # A simple container for a type alias
88 class Type:
89 def __init__(self,alias,dest):
90 self.alias=alias
91 self.dest=dest
93 # Parses a line of the form "COORD x, y; key" and returns a list of
94 # Field objects. types is a list of Type objects which are used to
95 # dereference type names.
96 def parse_fields(str, types):
97 mo=re.search(r"^\s*(\S+(?:\(.*\))?)\s+([^;()]*)\s*;\s*(.*)\s*$",str)
98 assert mo,str
99 arr=[]
100 for i in mo.groups():
101 if i:
102 arr.append(i.strip())
103 else:
104 arr.append("")
105 type,fields_,flags=arr
106 #print arr
108 # analyze type
109 while 1:
110 found=0
111 for i in types:
112 if i.alias==type:
113 type=i.dest
114 found=1
115 break
116 if not found:
117 break
119 typeinfo={}
120 mo=re.search("^(.*)\((.*)\)$",type)
121 assert mo,repr(type)
122 typeinfo["dataio_type"],typeinfo["struct_type"]=mo.groups()
124 if typeinfo["struct_type"]=="float":
125 mo=re.search("^(\D+)(\d+)$",typeinfo["dataio_type"])
126 assert mo
127 typeinfo["dataio_type"]=mo.group(1)
128 typeinfo["float_factor"]=int(mo.group(2))
130 # analyze fields
131 fields=[]
132 for i in fields_.split(","):
133 i=i.strip()
134 t={}
136 def f(x):
137 arr=x.split(":")
138 if len(arr)==1:
139 return [x,x,x]
140 else:
141 assert len(arr)==2
142 arr.append("old->"+arr[1])
143 arr[1]="real_packet->"+arr[1]
144 return arr
146 mo=re.search(r"^(.*)\[(.*)\]\[(.*)\]$",i)
147 if mo:
148 t["name"]=mo.group(1)
149 t["is_array"]=2
150 t["array_size1_d"],t["array_size1_u"],t["array_size1_o"]=f(mo.group(2))
151 t["array_size2_d"],t["array_size2_u"],t["array_size2_o"]=f(mo.group(3))
152 else:
153 mo=re.search(r"^(.*)\[(.*)\]$",i)
154 if mo:
155 t["name"]=mo.group(1)
156 t["is_array"]=1
157 t["array_size_d"],t["array_size_u"],t["array_size_o"]=f(mo.group(2))
158 else:
159 t["name"]=i
160 t["is_array"]=0
161 fields.append(t)
163 # analyze flags
164 flaginfo={}
165 arr=list(item.strip() for item in flags.split(","))
166 arr=list(filter(lambda x:len(x)>0,arr))
167 flaginfo["is_key"]=("key" in arr)
168 if flaginfo["is_key"]: arr.remove("key")
169 flaginfo["diff"]=("diff" in arr)
170 if flaginfo["diff"]: arr.remove("diff")
171 adds=[]
172 removes=[]
173 remaining=[]
174 for i in arr:
175 mo=re.search("^add-cap\((.*)\)$",i)
176 if mo:
177 adds.append(mo.group(1))
178 continue
179 mo=re.search("^remove-cap\((.*)\)$",i)
180 if mo:
181 removes.append(mo.group(1))
182 continue
183 remaining.append(i)
184 arr=remaining
185 assert len(arr)==0,repr(arr)
186 assert len(adds)+len(removes) in [0,1]
188 if adds:
189 flaginfo["add_cap"]=adds[0]
190 else:
191 flaginfo["add_cap"]=""
193 if removes:
194 flaginfo["remove_cap"]=removes[0]
195 else:
196 flaginfo["remove_cap"]=""
198 #print typeinfo,flaginfo,fields
199 result=[]
200 for f in fields:
201 result.append(Field(f,typeinfo,flaginfo))
202 return result
204 # Class for a field (part of a packet). It has a name, serveral types,
205 # flags and some other attributes.
206 class Field:
207 def __init__(self,fieldinfo,typeinfo,flaginfo):
208 for i in fieldinfo,typeinfo,flaginfo:
209 self.__dict__.update(i)
210 self.is_struct=not not re.search("^struct.*",self.struct_type)
212 # Helper function for the dictionary variant of the % operator
213 # ("%(name)s"%dict).
214 def get_dict(self,vars):
215 result=self.__dict__.copy()
216 result.update(vars)
217 return result
219 def get_handle_type(self):
220 if self.dataio_type=="string" or self.dataio_type=="estring":
221 return "const char *"
222 if self.dataio_type=="worklist":
223 return "const %s *"%self.struct_type
224 if self.is_array:
225 return "const %s *"%self.struct_type
226 return self.struct_type+" "
228 # Returns code which is used in the declaration of the field in
229 # the packet struct.
230 def get_declar(self):
231 if self.is_array==2:
232 return "%(struct_type)s %(name)s[%(array_size1_d)s][%(array_size2_d)s]"%self.__dict__
233 if self.is_array:
234 return "%(struct_type)s %(name)s[%(array_size_d)s]"%self.__dict__
235 else:
236 return "%(struct_type)s %(name)s"%self.__dict__
238 # Returns code which copies the arguments of the direct send
239 # functions in the packet struct.
240 def get_fill(self):
241 if self.dataio_type=="worklist":
242 return " worklist_copy(&real_packet->%(name)s, %(name)s);"%self.__dict__
243 if self.is_array==0:
244 return " real_packet->%(name)s = %(name)s;"%self.__dict__
245 if self.dataio_type=="string" or self.dataio_type=="estring":
246 return " sz_strlcpy(real_packet->%(name)s, %(name)s);"%self.__dict__
247 if self.is_array==1:
248 tmp="real_packet->%(name)s[i] = %(name)s[i]"%self.__dict__
249 return ''' {
250 int i;
252 for (i = 0; i < %(array_size_u) s; i++) {
253 %(tmp)s;
255 }'''%self.get_dict(vars())
257 return repr(self.__dict__)
259 # Returns code which sets "differ" by comparing the field
260 # instances of "old" and "readl_packet".
261 def get_cmp(self):
262 if self.dataio_type=="memory":
263 return " differ = (memcmp(old->%(name)s, real_packet->%(name)s, %(array_size_d)s) != 0);"%self.__dict__
264 if self.dataio_type=="bitvector":
265 return " differ = !BV_ARE_EQUAL(old->%(name)s, real_packet->%(name)s);"%self.__dict__
266 if self.dataio_type in ["string", "estring"] and self.is_array==1:
267 return " differ = (strcmp(old->%(name)s, real_packet->%(name)s) != 0);"%self.__dict__
268 if self.is_struct and self.is_array==0:
269 return " differ = !are_%(dataio_type)ss_equal(&old->%(name)s, &real_packet->%(name)s);"%self.__dict__
270 if not self.is_array:
271 return " differ = (old->%(name)s != real_packet->%(name)s);"%self.__dict__
273 if self.dataio_type=="string" or self.dataio_type=="estring":
274 c="strcmp(old->%(name)s[i], real_packet->%(name)s[i]) != 0"%self.__dict__
275 array_size_u=self.array_size1_u
276 array_size_o=self.array_size1_o
277 elif self.is_struct:
278 c="!are_%(dataio_type)ss_equal(&old->%(name)s[i], &real_packet->%(name)s[i])"%self.__dict__
279 else:
280 c="old->%(name)s[i] != real_packet->%(name)s[i]"%self.__dict__
282 return '''
284 differ = (%(array_size_o)s != %(array_size_u)s);
285 if (!differ) {
286 int i;
287 for (i = 0; i < %(array_size_u)s; i++) {
288 if (%(c)s) {
289 differ = TRUE;
290 break;
294 }'''%self.get_dict(vars())
296 # Returns a code fragment which updates the bit of the this field
297 # in the "fields" bitvector. The bit is either a "content-differs"
298 # bit or (for bools which gets folded in the header) the actual
299 # value of the bool.
300 def get_cmp_wrapper(self,i):
301 cmp=self.get_cmp()
302 if fold_bool_into_header and self.struct_type=="bool" and \
303 not self.is_array:
304 b="packet->%(name)s"%self.get_dict(vars())
305 return '''%s
306 if (differ) {
307 different++;
309 if (%s) {
310 BV_SET(fields, %d);
313 '''%(cmp,b,i)
314 else:
315 return '''%s
316 if (differ) {
317 different++;
318 BV_SET(fields, %d);
321 '''%(cmp,i)
323 # Returns a code fragment which will put this field if the
324 # content has changed. Does nothing for bools-in-header.
325 def get_put_wrapper(self,packet,i,deltafragment):
326 if fold_bool_into_header and self.struct_type=="bool" and \
327 not self.is_array:
328 return " /* field %(i)d is folded into the header */\n"%vars()
329 put=self.get_put(deltafragment)
330 packet_name=packet.name
331 log_macro=packet.log_macro
332 if packet.gen_log:
333 f=' %(log_macro)s(" field \'%(name)s\' has changed");\n'%self.get_dict(vars())
334 else:
335 f=""
336 if packet.gen_stats:
337 s=' stats_%(packet_name)s_counters[%(i)d]++;\n'%self.get_dict(vars())
338 else:
339 s=""
340 return ''' if (BV_ISSET(fields, %(i)d)) {
341 %(f)s%(s)s %(put)s
343 '''%self.get_dict(vars())
345 # Returns code which put this field.
346 def get_put(self,deltafragment):
347 return '''#ifdef FREECIV_JSON_CONNECTION
348 field_addr.name = \"%(name)s\";
349 #endif /* FREECIV_JSON_CONNECTION */
350 '''%self.__dict__ \
351 + self.get_put_real(deltafragment);
353 # The code which put this field before it is wrapped in address adding.
354 def get_put_real(self,deltafragment):
355 if self.dataio_type=="bitvector":
356 return "DIO_BV_PUT(&dout, &field_addr, packet->%(name)s);"%self.__dict__
358 if self.struct_type=="float" and not self.is_array:
359 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s, %(float_factor)d);"%self.__dict__
361 if self.dataio_type in ["worklist"]:
362 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s);"%self.__dict__
364 if self.dataio_type in ["memory"]:
365 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s, %(array_size_u)s);"%self.__dict__
367 arr_types=["string","estring","city_map","tech_list",
368 "unit_list","building_list"]
369 if (self.dataio_type in arr_types and self.is_array==1) or \
370 (self.dataio_type not in arr_types and self.is_array==0):
371 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s);"%self.__dict__
372 if self.is_struct:
373 if self.is_array==2:
374 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s[i][j]);"%self.__dict__
375 else:
376 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s[i]);"%self.__dict__
377 elif self.dataio_type=="string" or self.dataio_type=="estring":
378 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i]);"%self.__dict__
379 array_size_u=self.array_size1_u
381 elif self.struct_type=="float":
382 if self.is_array==2:
383 c=" DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i][j], %(float_factor)d);"%self.__dict__
384 else:
385 c=" DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i], %(float_factor)d);"%self.__dict__
386 else:
387 if self.is_array==2:
388 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i][j]);"%self.__dict__
389 else:
390 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i]);"%self.__dict__
392 if deltafragment and self.diff and self.is_array == 1:
393 return '''
395 int i;
397 #ifdef FREECIV_JSON_CONNECTION
398 int count = 0;
400 for (i = 0; i < %(array_size_u)s; i++) {
401 if (old->%(name)s[i] != real_packet->%(name)s[i]) {
402 count++;
405 /* Create the array. */
406 DIO_PUT(farray, &dout, &field_addr, count + 1);
408 /* Enter array. */
409 field_addr.sub_location = plocation_elem_new(0);
411 count = 0;
412 #endif /* FREECIV_JSON_CONNECTION */
414 fc_assert(%(array_size_u)s < 255);
416 for (i = 0; i < %(array_size_u)s; i++) {
417 if (old->%(name)s[i] != real_packet->%(name)s[i]) {
418 #ifdef FREECIV_JSON_CONNECTION
419 /* Next diff array element. */
420 field_addr.sub_location->number = count - 1;
422 /* Create the diff array element. */
423 DIO_PUT(farray, &dout, &field_addr, 2);
425 /* Enter diff array element (start at the index address). */
426 field_addr.sub_location->sub_location = plocation_elem_new(0);
427 #endif /* FREECIV_JSON_CONNECTION */
428 DIO_PUT(uint8, &dout, &field_addr, i);
430 #ifdef FREECIV_JSON_CONNECTION
431 /* Content address. */
432 field_addr.sub_location->sub_location->number = 1;
433 #endif /* FREECIV_JSON_CONNECTION */
434 %(c)s
436 #ifdef FREECIV_JSON_CONNECTION
437 /* Exit diff array element. */
438 free(field_addr.sub_location->sub_location);
439 field_addr.sub_location->sub_location = NULL;
440 #endif /* FREECIV_JSON_CONNECTION */
443 #ifdef FREECIV_JSON_CONNECTION
444 field_addr.sub_location->number = count - 1;
446 /* Create the diff array element. */
447 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
449 /* Enter diff array element. Point to index address. */
450 field_addr.sub_location->sub_location = plocation_elem_new(0);
451 #endif /* FREECIV_JSON_CONNECTION */
452 DIO_PUT(uint8, &dout, &field_addr, 255);
454 #ifdef FREECIV_JSON_CONNECTION
455 /* Exit diff array element. */
456 free(field_addr.sub_location->sub_location);
457 field_addr.sub_location->sub_location = NULL;
459 /* Exit array. */
460 free(field_addr.sub_location);
461 field_addr.sub_location = NULL;
462 #endif /* FREECIV_JSON_CONNECTION */
463 }'''%self.get_dict(vars())
464 if self.is_array == 2 and self.dataio_type != "string" \
465 and self.dataio_type != "estring":
466 return '''
468 int i, j;
470 #ifdef FREECIV_JSON_CONNECTION
471 /* Create the outer array. */
472 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
474 /* Enter the outer array. */
475 field_addr.sub_location = plocation_elem_new(0);
476 #endif /* FREECIV_JSON_CONNECTION */
478 for (i = 0; i < %(array_size1_u)s; i++) {
479 #ifdef FREECIV_JSON_CONNECTION
480 /* Next inner array (an element in the outer array). */
481 field_addr.sub_location->number = i;
483 /* Create the inner array. */
484 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
486 /* Enter the inner array. */
487 field_addr.sub_location->sub_location = plocation_elem_new(0);
488 #endif /* FREECIV_JSON_CONNECTION */
490 for (j = 0; j < %(array_size2_u)s; j++) {
491 #ifdef FREECIV_JSON_CONNECTION
492 /* Next element (in the inner array). */
493 field_addr.sub_location->sub_location->number = j;
494 #endif /* FREECIV_JSON_CONNECTION */
495 %(c)s
498 #ifdef FREECIV_JSON_CONNECTION
499 /* Exit the inner array. */
500 free(field_addr.sub_location->sub_location);
501 field_addr.sub_location->sub_location = NULL;
502 #endif /* FREECIV_JSON_CONNECTION */
505 #ifdef FREECIV_JSON_CONNECTION
506 /* Exit the outer array. */
507 free(field_addr.sub_location);
508 field_addr.sub_location = NULL;
509 #endif /* FREECIV_JSON_CONNECTION */
510 }'''%self.get_dict(vars())
511 else:
512 return '''
514 int i;
516 #ifdef FREECIV_JSON_CONNECTION
517 /* Create the array. */
518 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
520 /* Enter the array. */
521 field_addr.sub_location = plocation_elem_new(0);
522 #endif /* FREECIV_JSON_CONNECTION */
524 for (i = 0; i < %(array_size_u)s; i++) {
525 #ifdef FREECIV_JSON_CONNECTION
526 /* Next array element. */
527 field_addr.sub_location->number = i;
528 #endif /* FREECIV_JSON_CONNECTION */
529 %(c)s
532 #ifdef FREECIV_JSON_CONNECTION
533 /* Exit array. */
534 free(field_addr.sub_location);
535 field_addr.sub_location = NULL;
536 #endif /* FREECIV_JSON_CONNECTION */
537 }'''%self.get_dict(vars())
539 # Returns a code fragment which will get the field if the
540 # "fields" bitvector says so.
541 def get_get_wrapper(self,packet,i,deltafragment):
542 get=self.get_get(deltafragment)
543 if fold_bool_into_header and self.struct_type=="bool" and \
544 not self.is_array:
545 return " real_packet->%(name)s = BV_ISSET(fields, %(i)d);\n"%self.get_dict(vars())
546 get=prefix(" ",get)
547 log_macro=packet.log_macro
548 if packet.gen_log:
549 f=" %(log_macro)s(\" got field '%(name)s'\");\n"%self.get_dict(vars())
550 else:
551 f=""
552 return ''' if (BV_ISSET(fields, %(i)d)) {
553 %(f)s%(get)s
555 '''%self.get_dict(vars())
557 # Returns code which get this field.
558 def get_get(self,deltafragment):
559 return '''#ifdef FREECIV_JSON_CONNECTION
560 field_addr.name = \"%(name)s\";
561 #endif /* FREECIV_JSON_CONNECTION */
562 '''%self.__dict__ \
563 + self.get_get_real(deltafragment);
565 # The code which get this field before it is wrapped in address adding.
566 def get_get_real(self,deltafragment):
567 if self.struct_type=="float" and not self.is_array:
568 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s, %(float_factor)d)) {
569 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
570 }'''%self.__dict__
571 if self.dataio_type=="bitvector":
572 return '''if (!DIO_BV_GET(&din, &field_addr, real_packet->%(name)s)) {
573 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
574 }'''%self.__dict__
575 if self.dataio_type in ["string","estring","city_map"] and \
576 self.is_array!=2:
577 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, real_packet->%(name)s, sizeof(real_packet->%(name)s))) {
578 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
579 }'''%self.__dict__
580 if self.is_struct and self.is_array==0:
581 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s)) {
582 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
583 }'''%self.__dict__
584 if self.dataio_type in ["tech_list","unit_list","building_list"]:
585 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, real_packet->%(name)s)) {
586 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
587 }'''%self.__dict__
588 if not self.is_array:
589 if self.struct_type in ["int","bool"]:
590 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s)) {
591 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
592 }'''%self.__dict__
593 else:
594 return '''{
595 int readin;
597 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &readin)) {
598 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
600 real_packet->%(name)s = readin;
601 }'''%self.__dict__
603 if self.is_struct:
604 if self.is_array==2:
605 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i][j])) {
606 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
607 }'''%self.__dict__
608 else:
609 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i])) {
610 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
611 }'''%self.__dict__
612 elif self.dataio_type=="string" or self.dataio_type=="estring":
613 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, real_packet->%(name)s[i], sizeof(real_packet->%(name)s[i]))) {
614 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
615 }'''%self.__dict__
616 elif self.struct_type=="float":
617 if self.is_array==2:
618 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i][j], %(float_factor)d)) {
619 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
620 }'''%self.__dict__
621 else:
622 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i], %(float_factor)d)) {
623 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
624 }'''%self.__dict__
625 elif self.is_array==2:
626 if self.struct_type in ["int","bool"]:
627 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i][j])) {
628 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
629 }'''%self.__dict__
630 else:
631 c='''{
632 int readin;
634 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &readin)) {
635 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
637 real_packet->%(name)s[i][j] = readin;
638 }'''%self.__dict__
639 elif self.struct_type in ["int","bool"]:
640 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i])) {
641 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
642 }'''%self.__dict__
643 else:
644 c='''{
645 int readin;
647 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &readin)) {
648 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
650 real_packet->%(name)s[i] = readin;
651 }'''%self.__dict__
653 if self.is_array==2:
654 array_size_u=self.array_size1_u
655 array_size_d=self.array_size1_d
656 else:
657 array_size_u=self.array_size_u
658 array_size_d=self.array_size_d
660 if not self.diff or self.dataio_type=="memory":
661 if array_size_u != array_size_d:
662 extra='''
663 if (%(array_size_u)s > %(array_size_d)s) {
664 RECEIVE_PACKET_FIELD_ERROR(%(name)s, ": truncation array");
665 }'''%self.get_dict(vars())
666 else:
667 extra=""
668 if self.dataio_type=="memory":
669 return '''%(extra)s
670 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, real_packet->%(name)s, %(array_size_u)s)){
671 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
672 }'''%self.get_dict(vars())
673 elif self.is_array==2 and self.dataio_type!="string" \
674 and self.dataio_type!="estring":
675 return '''
677 int i, j;
679 #ifdef FREECIV_JSON_CONNECTION
680 /* Enter outer array. */
681 field_addr.sub_location = plocation_elem_new(0);
682 #endif /* FREECIV_JSON_CONNECTION */
683 %(extra)s
684 for (i = 0; i < %(array_size1_u)s; i++) {
685 #ifdef FREECIV_JSON_CONNECTION
686 /* Update address of outer array element (inner array). */
687 field_addr.sub_location->number = i;
689 /* Enter inner array. */
690 field_addr.sub_location->sub_location = plocation_elem_new(0);
691 #endif /* FREECIV_JSON_CONNECTION */
692 for (j = 0; j < %(array_size2_u)s; j++) {
693 #ifdef FREECIV_JSON_CONNECTION
694 /* Update address of element in inner array. */
695 field_addr.sub_location->sub_location->number = j;
696 #endif /* FREECIV_JSON_CONNECTION */
697 %(c)s
700 #ifdef FREECIV_JSON_CONNECTION
701 /* Exit inner array. */
702 free(field_addr.sub_location->sub_location);
703 field_addr.sub_location->sub_location = NULL;
704 #endif /* FREECIV_JSON_CONNECTION */
707 #ifdef FREECIV_JSON_CONNECTION
708 /* Exit outer array. */
709 free(field_addr.sub_location);
710 field_addr.sub_location = NULL;
711 #endif /* FREECIV_JSON_CONNECTION */
712 }'''%self.get_dict(vars())
713 else:
714 return '''
716 int i;
718 #ifdef FREECIV_JSON_CONNECTION
719 /* Enter array. */
720 field_addr.sub_location = plocation_elem_new(0);
721 #endif /* FREECIV_JSON_CONNECTION */
722 %(extra)s
723 for (i = 0; i < %(array_size_u)s; i++) {
724 #ifdef FREECIV_JSON_CONNECTION
725 field_addr.sub_location->number = i;
726 #endif /* FREECIV_JSON_CONNECTION */
727 %(c)s
730 #ifdef FREECIV_JSON_CONNECTION
731 /* Exit array. */
732 free(field_addr.sub_location);
733 field_addr.sub_location = NULL;
734 #endif /* FREECIV_JSON_CONNECTION */
735 }'''%self.get_dict(vars())
736 elif deltafragment and self.diff and self.is_array == 1:
737 return '''
739 int count;
741 #ifdef FREECIV_JSON_CONNECTION
742 /* Enter array. */
743 field_addr.sub_location = plocation_elem_new(0);
744 #endif /* FREECIV_JSON_CONNECTION */
746 for (count = 0;; count++) {
747 int i;
749 #ifdef FREECIV_JSON_CONNECTION
750 field_addr.sub_location->number = count;
752 /* Enter diff array element (start at the index address). */
753 field_addr.sub_location->sub_location = plocation_elem_new(0);
754 #endif /* FREECIV_JSON_CONNECTION */
756 if (!DIO_GET(uint8, &din, &field_addr, &i)) {
757 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
759 if (i == 255) {
760 #ifdef FREECIV_JSON_CONNECTION
761 /* Exit diff array element. */
762 free(field_addr.sub_location->sub_location);
763 field_addr.sub_location->sub_location = NULL;
765 /* Exit diff array. */
766 free(field_addr.sub_location);
767 field_addr.sub_location = NULL;
768 #endif /* FREECIV_JSON_CONNECTION */
770 break;
772 if (i > %(array_size_u)s) {
773 RECEIVE_PACKET_FIELD_ERROR(%(name)s,
774 \": unexpected value %%%%d \"
775 \"(> %(array_size_u)s) in array diff\",
777 } else {
778 #ifdef FREECIV_JSON_CONNECTION
779 /* Content address. */
780 field_addr.sub_location->sub_location->number = 1;
781 #endif /* FREECIV_JSON_CONNECTION */
782 %(c)s
785 #ifdef FREECIV_JSON_CONNECTION
786 /* Exit diff array element. */
787 free(field_addr.sub_location->sub_location);
788 field_addr.sub_location->sub_location = NULL;
789 #endif /* FREECIV_JSON_CONNECTION */
792 #ifdef FREECIV_JSON_CONNECTION
793 /* Exit array. */
794 free(field_addr.sub_location);
795 field_addr.sub_location = NULL;
796 #endif /* FREECIV_JSON_CONNECTION */
797 }'''%self.get_dict(vars())
798 else:
799 return '''
801 int i;
803 for (i = 0; i < %(array_size_u)s; i++) {
804 %(c)s
806 }'''%self.get_dict(vars())
809 # Class which represents a capability variant.
810 class Variant:
811 def __init__(self,poscaps,negcaps,name,fields,packet,no):
812 self.log_macro=use_log_macro
813 self.gen_stats=generate_stats
814 self.gen_log=generate_logs
815 self.name=name
816 self.packet_name=packet.name
817 self.fields=fields
818 self.no=no
820 self.no_packet=packet.no_packet
821 self.want_post_recv=packet.want_post_recv
822 self.want_pre_send=packet.want_pre_send
823 self.want_post_send=packet.want_post_send
824 self.type=packet.type
825 self.delta=packet.delta
826 self.is_info=packet.is_info
827 self.cancel=packet.cancel
828 self.want_force=packet.want_force
830 self.poscaps=poscaps
831 self.negcaps=negcaps
832 if self.poscaps or self.negcaps:
833 def f(cap):
834 return 'has_capability("%s", capability)'%(cap)
835 t=(list(map(lambda x,f=f: f(x),self.poscaps))+
836 list(map(lambda x,f=f: '!'+f(x),self.negcaps)))
837 self.condition=" && ".join(t)
838 else:
839 self.condition="TRUE"
840 self.key_fields=list(filter(lambda x:x.is_key,self.fields))
841 self.other_fields=list(filter(lambda x:not x.is_key,self.fields))
842 self.bits=len(self.other_fields)
843 self.keys_format=", ".join(["%d"]*len(self.key_fields))
844 self.keys_arg=", ".join(map(lambda x:"real_packet->"+x.name,
845 self.key_fields))
846 if self.keys_arg:
847 self.keys_arg=",\n "+self.keys_arg
849 if len(self.fields)==0:
850 self.delta=0
851 self.no_packet=1
853 if len(self.fields)>5 or self.name.split("_")[1]=="ruleset":
854 self.handle_via_packet=1
856 self.extra_send_args=""
857 self.extra_send_args2=""
858 self.extra_send_args3=", ".join(
859 map(lambda x:"%s%s"%(x.get_handle_type(), x.name),
860 self.fields))
861 if self.extra_send_args3:
862 self.extra_send_args3=", "+self.extra_send_args3
864 if not self.no_packet:
865 self.extra_send_args=', const struct %(packet_name)s *packet'%self.__dict__+self.extra_send_args
866 self.extra_send_args2=', packet'+self.extra_send_args2
868 if self.want_force:
869 self.extra_send_args=self.extra_send_args+', bool force_to_send'
870 self.extra_send_args2=self.extra_send_args2+', force_to_send'
871 self.extra_send_args3=self.extra_send_args3+', bool force_to_send'
873 self.receive_prototype='static struct %(packet_name)s *receive_%(name)s(struct connection *pc)'%self.__dict__
874 self.send_prototype='static int send_%(name)s(struct connection *pc%(extra_send_args)s)'%self.__dict__
877 if self.no_packet:
878 self.send_handler='phandlers->send[%(type)s].no_packet = (int(*)(struct connection *)) send_%(name)s;'%self.__dict__
879 elif self.want_force:
880 self.send_handler='phandlers->send[%(type)s].force_to_send = (int(*)(struct connection *, const void *, bool)) send_%(name)s;'%self.__dict__
881 else:
882 self.send_handler='phandlers->send[%(type)s].packet = (int(*)(struct connection *, const void *)) send_%(name)s;'%self.__dict__
883 self.receive_handler='phandlers->receive[%(type)s] = (void *(*)(struct connection *)) receive_%(name)s;'%self.__dict__
885 # See Field.get_dict
886 def get_dict(self,vars):
887 result=self.__dict__.copy()
888 result.update(vars)
889 return result
891 # Returns a code fragment which contains the declarations of the
892 # statistical counters of this packet.
893 def get_stats(self):
894 names=map(lambda x:'"'+x.name+'"',self.other_fields)
895 names=", ".join(names)
897 return '''static int stats_%(name)s_sent;
898 static int stats_%(name)s_discarded;
899 static int stats_%(name)s_counters[%(bits)d];
900 static char *stats_%(name)s_names[] = {%(names)s};
902 '''%self.get_dict(vars())
904 # Returns a code fragment which declares the packet specific
905 # bitvector. Each bit in this bitvector represents one non-key
906 # field.
907 def get_bitvector(self):
908 return "BV_DEFINE(%(name)s_fields, %(bits)d);\n"%self.__dict__
910 # Returns a code fragment which is the packet specific part of
911 # the delta_stats_report() function.
912 def get_report_part(self):
913 return '''
914 if (stats_%(name)s_sent > 0 &&
915 stats_%(name)s_discarded != stats_%(name)s_sent) {
916 log_test(\"%(name)s %%d out of %%d got discarded\",
917 stats_%(name)s_discarded, stats_%(name)s_sent);
918 for (i = 0; i < %(bits)d; i++) {
919 if (stats_%(name)s_counters[i] > 0) {
920 log_test(\" %%4d / %%4d: %%2d = %%s\",
921 stats_%(name)s_counters[i],
922 (stats_%(name)s_sent - stats_%(name)s_discarded),
923 i, stats_%(name)s_names[i]);
927 '''%self.__dict__
929 # Returns a code fragment which is the packet specific part of
930 # the delta_stats_reset() function.
931 def get_reset_part(self):
932 return '''
933 stats_%(name)s_sent = 0;
934 stats_%(name)s_discarded = 0;
935 memset(stats_%(name)s_counters, 0,
936 sizeof(stats_%(name)s_counters));
937 '''%self.__dict__
939 # Returns a code fragment which is the implementation of the hash
940 # function. The hash function is using all key fields.
941 def get_hash(self):
942 if len(self.key_fields)==0:
943 return "#define hash_%(name)s hash_const\n\n"%self.__dict__
944 else:
945 intro='''static genhash_val_t hash_%(name)s(const void *vkey)
947 '''%self.__dict__
949 body=''' const struct %(packet_name)s *key = (const struct %(packet_name)s *) vkey;
951 '''%self.__dict__
953 keys=list(map(lambda x:"key->"+x.name,self.key_fields))
954 if len(keys)==1:
955 a=keys[0]
956 elif len(keys)==2:
957 a="(%s << 8) ^ %s"%(keys[0], keys[1])
958 else:
959 assert 0
960 body=body+(' return %s;\n'%a)
961 extro="}\n\n"
962 return intro+body+extro
964 # Returns a code fragment which is the implementation of the cmp
965 # function. The cmp function is using all key fields. The cmp
966 # function is used for the hash table.
967 def get_cmp(self):
968 if len(self.key_fields)==0:
969 return "#define cmp_%(name)s cmp_const\n\n"%self.__dict__
970 else:
971 intro='''static bool cmp_%(name)s(const void *vkey1, const void *vkey2)
973 '''%self.__dict__
974 body=""
975 body=body+''' const struct %(packet_name)s *key1 = (const struct %(packet_name)s *) vkey1;
976 const struct %(packet_name)s *key2 = (const struct %(packet_name)s *) vkey2;
978 '''%self.__dict__
979 for field in self.key_fields:
980 body=body+''' return key1->%s == key2->%s;
981 '''%(field.name,field.name)
982 extro="}\n"
983 return intro+body+extro
985 # Returns a code fragment which is the implementation of the send
986 # function. This is one of the two real functions. So it is rather
987 # complex to create.
988 def get_send(self):
989 temp='''%(send_prototype)s
991 <real_packet1><delta_header> SEND_PACKET_START(%(type)s);
992 <faddr><log><report><pre1><body><pre2><post> SEND_PACKET_END(%(type)s);
996 if self.gen_stats:
997 report='''
998 stats_total_sent++;
999 stats_%(name)s_sent++;
1001 else:
1002 report=""
1003 if self.gen_log:
1004 log='\n %(log_macro)s("%(name)s: sending info about (%(keys_format)s)"%(keys_arg)s);\n'
1005 else:
1006 log=""
1007 if self.want_pre_send:
1008 pre1='''
1010 struct %(packet_name)s *tmp = fc_malloc(sizeof(*tmp));
1012 *tmp = *packet;
1013 pre_send_%(packet_name)s(pc, tmp);
1014 real_packet = tmp;
1017 pre2='''
1018 if (real_packet != packet) {
1019 free((void *) real_packet);
1022 else:
1023 pre1=""
1024 pre2=""
1026 if not self.no_packet:
1027 real_packet1=" const struct %(packet_name)s *real_packet = packet;\n"
1028 else:
1029 real_packet1=""
1031 if not self.no_packet:
1032 if self.delta:
1033 if self.want_force:
1034 diff='force_to_send'
1035 else:
1036 diff='0'
1037 delta_header='''#ifdef FREECIV_DELTA_PROTOCOL
1038 %(name)s_fields fields;
1039 struct %(packet_name)s *old;
1040 bool differ;
1041 struct genhash **hash = pc->phs.sent + %(type)s;
1042 int different = %(diff)s;
1043 #endif /* FREECIV_DELTA_PROTOCOL */
1045 body=self.get_delta_send_body()+"\n#ifndef FREECIV_DELTA_PROTOCOL"
1046 else:
1047 delta_header=""
1048 body="#if 1 /* To match endif */"
1049 body=body+"\n"
1050 for field in self.fields:
1051 body=body+field.get_put(0)+"\n"
1052 body=body+"\n#endif\n"
1053 else:
1054 body=""
1055 delta_header=""
1057 if self.want_post_send:
1058 if self.no_packet:
1059 post=" post_send_%(packet_name)s(pc, NULL);\n"
1060 else:
1061 post=" post_send_%(packet_name)s(pc, real_packet);\n"
1062 else:
1063 post=""
1065 if len(self.fields) != 0:
1066 faddr = '''#ifdef FREECIV_JSON_CONNECTION
1067 struct plocation field_addr = *plocation_field_new(NULL);
1068 #endif /* FREECIV_JSON_CONNECTION */
1070 else:
1071 faddr = ""
1073 for i in range(2):
1074 for k,v in vars().items():
1075 if type(v)==type(""):
1076 temp=temp.replace("<%s>"%k,v)
1077 return temp%self.get_dict(vars())
1079 # '''
1081 # Helper for get_send()
1082 def get_delta_send_body(self):
1083 intro='''
1084 #ifdef FREECIV_DELTA_PROTOCOL
1085 if (NULL == *hash) {
1086 *hash = genhash_new_full(hash_%(name)s, cmp_%(name)s,
1087 NULL, NULL, NULL, free);
1089 BV_CLR_ALL(fields);
1091 if (!genhash_lookup(*hash, real_packet, (void **) &old)) {
1092 old = fc_malloc(sizeof(*old));
1093 *old = *real_packet;
1094 genhash_insert(*hash, old, old);
1095 memset(old, 0, sizeof(*old));
1096 different = 1; /* Force to send. */
1099 body=""
1100 for i in range(len(self.other_fields)):
1101 field=self.other_fields[i]
1102 body=body+field.get_cmp_wrapper(i)
1103 if self.gen_log:
1104 fl=' %(log_macro)s(" no change -> discard");\n'
1105 else:
1106 fl=""
1107 if self.gen_stats:
1108 s=' stats_%(name)s_discarded++;\n'
1109 else:
1110 s=""
1112 if self.is_info != "no":
1113 body=body+'''
1114 if (different == 0) {
1115 %(fl)s%(s)s<pre2> return 0;
1117 '''%self.get_dict(vars())
1119 body=body+'''
1120 #ifdef FREECIV_JSON_CONNECTION
1121 field_addr.name = "fields";
1122 #endif /* FREECIV_JSON_CONNECTION */
1123 DIO_BV_PUT(&dout, &field_addr, fields);
1126 for field in self.key_fields:
1127 body=body+field.get_put(1)+"\n"
1128 body=body+"\n"
1130 for i in range(len(self.other_fields)):
1131 field=self.other_fields[i]
1132 body=body+field.get_put_wrapper(self,i,1)
1133 body=body+'''
1134 *old = *real_packet;
1137 # Cancel some is-info packets.
1138 for i in self.cancel:
1139 body=body+'''
1140 hash = pc->phs.sent + %s;
1141 if (NULL != *hash) {
1142 genhash_remove(*hash, real_packet);
1144 '''%i
1145 body=body+'''#endif /* FREECIV_DELTA_PROTOCOL */'''
1147 return intro+body
1149 # Returns a code fragment which is the implementation of the receive
1150 # function. This is one of the two real functions. So it is rather
1151 # complex to create.
1152 def get_receive(self):
1153 temp='''%(receive_prototype)s
1155 <delta_header> RECEIVE_PACKET_START(%(packet_name)s, real_packet);
1156 <faddr><delta_body1><body1><log><body2><post> RECEIVE_PACKET_END(real_packet);
1160 if self.delta:
1161 delta_header='''#ifdef FREECIV_DELTA_PROTOCOL
1162 %(name)s_fields fields;
1163 struct %(packet_name)s *old;
1164 struct genhash **hash = pc->phs.received + %(type)s;
1165 #endif /* FREECIV_DELTA_PROTOCOL */
1167 delta_body1='''
1168 #ifdef FREECIV_DELTA_PROTOCOL
1169 #ifdef FREECIV_JSON_CONNECTION
1170 field_addr.name = "fields";
1171 #endif /* FREECIV_JSON_CONNECTION */
1172 DIO_BV_GET(&din, &field_addr, fields);
1174 body1=""
1175 for field in self.key_fields:
1176 body1=body1+prefix(" ",field.get_get(1))+"\n"
1177 body1=body1+"\n#else /* FREECIV_DELTA_PROTOCOL */\n"
1178 body2=self.get_delta_receive_body()
1179 else:
1180 delta_header=""
1181 delta_body1=""
1182 body1="#if 1 /* To match endif */\n"
1183 body2=""
1184 nondelta=""
1185 for field in self.fields:
1186 nondelta=nondelta+prefix(" ",field.get_get(0))+"\n"
1187 if not nondelta:
1188 nondelta=" real_packet->__dummy = 0xff;"
1189 body1=body1+nondelta+"\n#endif\n"
1191 if self.gen_log:
1192 log=' %(log_macro)s("%(name)s: got info about (%(keys_format)s)"%(keys_arg)s);\n'
1193 else:
1194 log=""
1196 if self.want_post_recv:
1197 post=" post_receive_%(packet_name)s(pc, real_packet);\n"
1198 else:
1199 post=""
1201 if len(self.fields) != 0:
1202 faddr = '''#ifdef FREECIV_JSON_CONNECTION
1203 struct plocation field_addr = *plocation_field_new(NULL);
1204 #endif /* FREECIV_JSON_CONNECTION */
1206 else:
1207 faddr = ""
1209 for i in range(2):
1210 for k,v in vars().items():
1211 if type(v)==type(""):
1212 temp=temp.replace("<%s>"%k,v)
1213 return temp%self.get_dict(vars())
1215 # Helper for get_receive()
1216 def get_delta_receive_body(self):
1217 key1=map(lambda x:" %s %s = real_packet->%s;"%(x.struct_type,x.name,x.name),self.key_fields)
1218 key2=map(lambda x:" real_packet->%s = %s;"%(x.name,x.name),self.key_fields)
1219 key1="\n".join(key1)
1220 key2="\n".join(key2)
1221 if key1: key1=key1+"\n\n"
1222 if key2: key2="\n\n"+key2
1223 if self.gen_log:
1224 fl=' %(log_macro)s(" no old info");\n'
1225 else:
1226 fl=""
1227 body='''
1228 #ifdef FREECIV_DELTA_PROTOCOL
1229 if (NULL == *hash) {
1230 *hash = genhash_new_full(hash_%(name)s, cmp_%(name)s,
1231 NULL, NULL, NULL, free);
1234 if (genhash_lookup(*hash, real_packet, (void **) &old)) {
1235 *real_packet = *old;
1236 } else {
1237 %(key1)s%(fl)s memset(real_packet, 0, sizeof(*real_packet));%(key2)s
1240 '''%self.get_dict(vars())
1241 for i in range(len(self.other_fields)):
1242 field=self.other_fields[i]
1243 body=body+field.get_get_wrapper(self,i,1)
1245 extro='''
1246 if (NULL == old) {
1247 old = fc_malloc(sizeof(*old));
1248 *old = *real_packet;
1249 genhash_insert(*hash, old, old);
1250 } else {
1251 *old = *real_packet;
1253 '''%self.get_dict(vars())
1255 # Cancel some is-info packets.
1256 for i in self.cancel:
1257 extro=extro+'''
1258 hash = pc->phs.received + %s;
1259 if (NULL != *hash) {
1260 genhash_remove(*hash, real_packet);
1262 '''%i
1264 return body+extro+'''
1265 #endif /* FREECIV_DELTA_PROTOCOL */
1268 # Class which represents a packet. A packet contains a list of fields.
1269 class Packet:
1270 def __init__(self,str, types):
1271 self.types=types
1272 self.log_macro=use_log_macro
1273 self.gen_stats=generate_stats
1274 self.gen_log=generate_logs
1275 str=str.strip()
1276 lines=str.split("\n")
1278 mo=re.search("^\s*(\S+)\s*=\s*(\d+)\s*;\s*(.*?)\s*$",lines[0])
1279 assert mo,repr(lines[0])
1281 self.type=mo.group(1)
1282 self.name=self.type.lower()
1283 self.type_number=int(mo.group(2))
1284 assert 0<=self.type_number<=65535
1285 dummy=mo.group(3)
1287 del lines[0]
1289 arr=list(item.strip() for item in dummy.split(",") if item)
1291 self.dirs=[]
1293 if "sc" in arr:
1294 self.dirs.append("sc")
1295 arr.remove("sc")
1296 if "cs" in arr:
1297 self.dirs.append("cs")
1298 arr.remove("cs")
1299 assert len(self.dirs)>0,repr(self.name)+repr(self.dirs)
1301 # "no" means normal packet
1302 # "yes" means is-info packet
1303 # "game" means is-game-info packet
1304 self.is_info="no"
1305 if "is-info" in arr:
1306 self.is_info="yes"
1307 arr.remove("is-info")
1308 if "is-game-info" in arr:
1309 self.is_info="game"
1310 arr.remove("is-game-info")
1312 self.want_pre_send="pre-send" in arr
1313 if self.want_pre_send: arr.remove("pre-send")
1315 self.want_post_recv="post-recv" in arr
1316 if self.want_post_recv: arr.remove("post-recv")
1318 self.want_post_send="post-send" in arr
1319 if self.want_post_send: arr.remove("post-send")
1321 self.delta="no-delta" not in arr
1322 if not self.delta: arr.remove("no-delta")
1324 self.no_packet="no-packet" in arr
1325 if self.no_packet: arr.remove("no-packet")
1327 self.handle_via_packet="handle-via-packet" in arr
1328 if self.handle_via_packet: arr.remove("handle-via-packet")
1330 self.handle_per_conn="handle-per-conn" in arr
1331 if self.handle_per_conn: arr.remove("handle-per-conn")
1333 self.no_handle="no-handle" in arr
1334 if self.no_handle: arr.remove("no-handle")
1336 self.dsend_given="dsend" in arr
1337 if self.dsend_given: arr.remove("dsend")
1339 self.want_lsend="lsend" in arr
1340 if self.want_lsend: arr.remove("lsend")
1342 self.want_force="force" in arr
1343 if self.want_force: arr.remove("force")
1345 self.cancel=[]
1346 removes=[]
1347 remaining=[]
1348 for i in arr:
1349 mo=re.search("^cancel\((.*)\)$",i)
1350 if mo:
1351 self.cancel.append(mo.group(1))
1352 continue
1353 remaining.append(i)
1354 arr=remaining
1356 assert len(arr)==0,repr(arr)
1358 self.fields=[]
1359 for i in lines:
1360 self.fields=self.fields+parse_fields(i,types)
1361 self.key_fields=list(filter(lambda x:x.is_key,self.fields))
1362 self.other_fields=list(filter(lambda x:not x.is_key,self.fields))
1363 self.bits=len(self.other_fields)
1364 self.keys_format=", ".join(["%d"]*len(self.key_fields))
1365 self.keys_arg=", ".join(map(lambda x:"real_packet->"+x.name,
1366 self.key_fields))
1367 if self.keys_arg:
1368 self.keys_arg=",\n "+self.keys_arg
1371 self.want_dsend=self.dsend_given
1373 if len(self.fields)==0:
1374 self.delta=0
1375 self.no_packet=1
1376 assert not self.want_dsend,"dsend for a packet without fields isn't useful"
1378 if len(self.fields)>5 or self.name.split("_")[1]=="ruleset":
1379 self.handle_via_packet=1
1381 self.extra_send_args=""
1382 self.extra_send_args2=""
1383 self.extra_send_args3=", ".join(
1384 map(lambda x:"%s%s"%(x.get_handle_type(), x.name),
1385 self.fields))
1386 if self.extra_send_args3:
1387 self.extra_send_args3=", "+self.extra_send_args3
1389 if not self.no_packet:
1390 self.extra_send_args=', const struct %(name)s *packet'%self.__dict__+self.extra_send_args
1391 self.extra_send_args2=', packet'+self.extra_send_args2
1393 if self.want_force:
1394 self.extra_send_args=self.extra_send_args+', bool force_to_send'
1395 self.extra_send_args2=self.extra_send_args2+', force_to_send'
1396 self.extra_send_args3=self.extra_send_args3+', bool force_to_send'
1398 self.send_prototype='int send_%(name)s(struct connection *pc%(extra_send_args)s)'%self.__dict__
1399 if self.want_lsend:
1400 self.lsend_prototype='void lsend_%(name)s(struct conn_list *dest%(extra_send_args)s)'%self.__dict__
1401 if self.want_dsend:
1402 self.dsend_prototype='int dsend_%(name)s(struct connection *pc%(extra_send_args3)s)'%self.__dict__
1403 if self.want_lsend:
1404 self.dlsend_prototype='void dlsend_%(name)s(struct conn_list *dest%(extra_send_args3)s)'%self.__dict__
1406 # create cap variants
1407 all_caps={}
1408 for f in self.fields:
1409 if f.add_cap: all_caps[f.add_cap]=1
1410 if f.remove_cap: all_caps[f.remove_cap]=1
1412 all_caps=all_caps.keys()
1413 choices=get_choices(all_caps)
1414 self.variants=[]
1415 for i in range(len(choices)):
1416 poscaps=choices[i]
1417 negcaps=without(all_caps,poscaps)
1418 fields=[]
1419 for field in self.fields:
1420 if not field.add_cap and not field.remove_cap:
1421 fields.append(field)
1422 elif field.add_cap and field.add_cap in poscaps:
1423 fields.append(field)
1424 elif field.remove_cap and field.remove_cap in negcaps:
1425 fields.append(field)
1426 no=i+100
1428 self.variants.append(Variant(poscaps,negcaps,"%s_%d"%(self.name,no),fields,self,no))
1431 # Returns a code fragment which contains the struct for this packet.
1432 def get_struct(self):
1433 intro="struct %(name)s {\n"%self.__dict__
1434 extro="};\n\n"
1436 body=""
1437 for field in self.key_fields+self.other_fields:
1438 body=body+" %s;\n"%field.get_declar()
1439 if not body:
1440 body=" char __dummy; /* to avoid malloc(0); */\n"
1441 return intro+body+extro
1442 # '''
1444 # Returns a code fragment which represents the prototypes of the
1445 # send and receive functions for the header file.
1446 def get_prototypes(self):
1447 result=self.send_prototype+";\n"
1448 if self.want_lsend:
1449 result=result+self.lsend_prototype+";\n"
1450 if self.want_dsend:
1451 result=result+self.dsend_prototype+";\n"
1452 if self.want_lsend:
1453 result=result+self.dlsend_prototype+";\n"
1454 return result+"\n"
1456 # See Field.get_dict
1457 def get_dict(self,vars):
1458 result=self.__dict__.copy()
1459 result.update(vars)
1460 return result
1462 def get_send(self):
1463 if self.no_packet:
1464 func="no_packet"
1465 args=""
1466 elif self.want_force:
1467 func="force_to_send"
1468 args=", packet, force_to_send"
1469 else:
1470 func="packet"
1471 args=", packet"
1473 return '''%(send_prototype)s
1475 if (!pc->used) {
1476 log_error("WARNING: trying to send data to the closed connection %%s",
1477 conn_description(pc));
1478 return -1;
1480 fc_assert_ret_val_msg(pc->phs.handlers->send[%(type)s].%(func)s != NULL, -1,
1481 "Handler for %(type)s not installed");
1482 return pc->phs.handlers->send[%(type)s].%(func)s(pc%(args)s);
1485 '''%self.get_dict(vars())
1487 def get_variants(self):
1488 result=""
1489 for v in self.variants:
1490 if v.delta:
1491 result=result+"#ifdef FREECIV_DELTA_PROTOCOL\n"
1492 result=result+v.get_hash()
1493 result=result+v.get_cmp()
1494 result=result+v.get_bitvector()
1495 result=result+"#endif /* FREECIV_DELTA_PROTOCOL */\n\n"
1496 result=result+v.get_receive()
1497 result=result+v.get_send()
1498 return result
1500 # Returns a code fragment which is the implementation of the
1501 # lsend function.
1502 def get_lsend(self):
1503 if not self.want_lsend: return ""
1504 return '''%(lsend_prototype)s
1506 conn_list_iterate(dest, pconn) {
1507 send_%(name)s(pconn%(extra_send_args2)s);
1508 } conn_list_iterate_end;
1511 '''%self.__dict__
1513 # Returns a code fragment which is the implementation of the
1514 # dsend function.
1515 def get_dsend(self):
1516 if not self.want_dsend: return ""
1517 fill="\n".join(map(lambda x:x.get_fill(),self.fields))
1518 return '''%(dsend_prototype)s
1520 struct %(name)s packet, *real_packet = &packet;
1522 %(fill)s
1524 return send_%(name)s(pc, real_packet);
1527 '''%self.get_dict(vars())
1529 # Returns a code fragment which is the implementation of the
1530 # dlsend function.
1531 def get_dlsend(self):
1532 if not (self.want_lsend and self.want_dsend): return ""
1533 fill="\n".join(map(lambda x:x.get_fill(),self.fields))
1534 return '''%(dlsend_prototype)s
1536 struct %(name)s packet, *real_packet = &packet;
1538 %(fill)s
1540 lsend_%(name)s(dest, real_packet);
1543 '''%self.get_dict(vars())
1545 # Returns a code fragment which is the implementation of the
1546 # packet_functional_capability string.
1547 def get_packet_functional_capability(packets):
1548 all_caps={}
1549 for p in packets:
1550 for f in p.fields:
1551 if f.add_cap: all_caps[f.add_cap]=1
1552 if f.remove_cap: all_caps[f.remove_cap]=1
1553 return '''
1554 const char *const packet_functional_capability = "%s";
1555 '''%' '.join(all_caps.keys())
1557 # Returns a code fragment which is the implementation of the
1558 # delta_stats_report() function.
1559 def get_report(packets):
1560 if not generate_stats: return 'void delta_stats_report(void) {}\n\n'
1562 intro='''
1563 void delta_stats_report(void) {
1564 int i;
1567 extro='}\n\n'
1568 body=""
1570 for p in packets:
1571 body=body+p.get_report_part()
1572 return intro+body+extro
1574 # Returns a code fragment which is the implementation of the
1575 # delta_stats_reset() function.
1576 def get_reset(packets):
1577 if not generate_stats: return 'void delta_stats_reset(void) {}\n\n'
1578 intro='''
1579 void delta_stats_reset(void) {
1581 extro='}\n\n'
1582 body=""
1584 for p in packets:
1585 body=body+p.get_reset_part()
1586 return intro+body+extro
1588 # Returns a code fragment which is the implementation of the
1589 # packet_name() function.
1590 def get_packet_name(packets):
1591 intro='''const char *packet_name(enum packet_type type)
1593 static const char *const names[PACKET_LAST] = {
1596 mapping={}
1597 for p in packets:
1598 mapping[p.type_number]=p
1599 sorted=list(mapping.keys())
1600 sorted.sort()
1602 last=-1
1603 body=""
1604 for n in sorted:
1605 for i in range(last + 1, n):
1606 body=body+' "unknown",\n'
1607 body=body+' "%s",\n'%mapping[n].type
1608 last=n
1610 extro=''' };
1612 return (type >= 0 && type < PACKET_LAST ? names[type] : "unknown");
1616 return intro+body+extro
1618 # Returns a code fragment which is the implementation of the
1619 # packet_has_game_info_flag() function.
1620 def get_packet_has_game_info_flag(packets):
1621 intro='''bool packet_has_game_info_flag(enum packet_type type)
1623 static const bool flag[PACKET_LAST] = {
1626 mapping={}
1627 for p in packets:
1628 mapping[p.type_number]=p
1629 sorted=list(mapping.keys())
1630 sorted.sort()
1632 last=-1
1633 body=""
1634 for n in sorted:
1635 for i in range(last + 1, n):
1636 body=body+' FALSE,\n'
1637 if mapping[n].is_info!="game":
1638 body=body+' FALSE, /* %s */\n'%mapping[n].type
1639 else:
1640 body=body+' TRUE, /* %s */\n'%mapping[n].type
1641 last=n
1643 extro=''' };
1645 return (type >= 0 && type < PACKET_LAST ? flag[type] : FALSE);
1649 return intro+body+extro
1651 # Returns a code fragment which is the implementation of the
1652 # packet_handlers_fill_initial() function.
1653 def get_packet_handlers_fill_initial(packets):
1654 intro='''void packet_handlers_fill_initial(struct packet_handlers *phandlers)
1657 all_caps={}
1658 for p in packets:
1659 for f in p.fields:
1660 if f.add_cap: all_caps[f.add_cap]=1
1661 if f.remove_cap: all_caps[f.remove_cap]=1
1662 for cap in all_caps.keys():
1663 intro=intro+''' fc_assert_msg(has_capability("%s", our_capability),
1664 "Packets have support for unknown '%s' capability!");
1665 '''%(cap,cap)
1667 sc_packets=[]
1668 cs_packets=[]
1669 unrestricted=[]
1670 for p in packets:
1671 if len(p.variants)==1:
1672 # Packets with variants are correctly handled in
1673 # packet_handlers_fill_capability(). They may remain without
1674 # handler at connecting time, because it would be anyway wrong
1675 # to use them before the network capability string would be
1676 # known.
1677 if len(p.dirs)==1 and p.dirs[0]=="sc":
1678 sc_packets.append(p)
1679 elif len(p.dirs)==1 and p.dirs[0]=="cs":
1680 cs_packets.append(p)
1681 else:
1682 unrestricted.append(p)
1684 body=""
1685 for p in unrestricted:
1686 body=body+''' %(send_handler)s
1687 %(receive_handler)s
1688 '''%p.variants[0].__dict__
1689 body=body+''' if (is_server()) {
1691 for p in sc_packets:
1692 body=body+''' %(send_handler)s
1693 '''%p.variants[0].__dict__
1694 for p in cs_packets:
1695 body=body+''' %(receive_handler)s
1696 '''%p.variants[0].__dict__
1697 body=body+''' } else {
1699 for p in cs_packets:
1700 body=body+''' %(send_handler)s
1701 '''%p.variants[0].__dict__
1702 for p in sc_packets:
1703 body=body+''' %(receive_handler)s
1704 '''%p.variants[0].__dict__
1706 extro=''' }
1710 return intro+body+extro
1712 # Returns a code fragment which is the implementation of the
1713 # packet_handlers_fill_capability() function.
1714 def get_packet_handlers_fill_capability(packets):
1715 intro='''void packet_handlers_fill_capability(struct packet_handlers *phandlers,
1716 const char *capability)
1720 sc_packets=[]
1721 cs_packets=[]
1722 unrestricted=[]
1723 for p in packets:
1724 if len(p.variants)>1:
1725 if len(p.dirs)==1 and p.dirs[0]=="sc":
1726 sc_packets.append(p)
1727 elif len(p.dirs)==1 and p.dirs[0]=="cs":
1728 cs_packets.append(p)
1729 else:
1730 unrestricted.append(p)
1732 body=""
1733 for p in unrestricted:
1734 body=body+" "
1735 for v in p.variants:
1736 body=body+'''if (%(condition)s) {
1737 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1738 %(send_handler)s
1739 %(receive_handler)s
1740 } else '''%v.__dict__
1741 body=body+'''{
1742 log_error("Unknown %(type)s variant for cap %%s", capability);
1744 '''%v.__dict__
1745 if len(cs_packets)>0 or len(sc_packets)>0:
1746 body=body+''' if (is_server()) {
1748 for p in sc_packets:
1749 body=body+" "
1750 for v in p.variants:
1751 body=body+'''if (%(condition)s) {
1752 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1753 %(send_handler)s
1754 } else '''%v.__dict__
1755 body=body+'''{
1756 log_error("Unknown %(type)s variant for cap %%s", capability);
1758 '''%v.__dict__
1759 for p in cs_packets:
1760 body=body+" "
1761 for v in p.variants:
1762 body=body+'''if (%(condition)s) {
1763 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1764 %(receive_handler)s
1765 } else '''%v.__dict__
1766 body=body+'''{
1767 log_error("Unknown %(type)s variant for cap %%s", capability);
1769 '''%v.__dict__
1770 body=body+''' } else {
1772 for p in cs_packets:
1773 body=body+" "
1774 for v in p.variants:
1775 body=body+'''if (%(condition)s) {
1776 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1777 %(send_handler)s
1778 } else '''%v.__dict__
1779 body=body+'''{
1780 log_error("Unknown %(type)s variant for cap %%s", capability);
1782 '''%v.__dict__
1783 for p in sc_packets:
1784 body=body+" "
1785 for v in p.variants:
1786 body=body+'''if (%(condition)s) {
1787 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1788 %(receive_handler)s
1789 } else '''%v.__dict__
1790 body=body+'''{
1791 log_error("Unknown %(type)s variant for cap %%s", capability);
1793 '''%v.__dict__
1794 body=body+''' }
1797 extro='''}
1799 return intro+body+extro
1801 # Returns a code fragment which is the declartion of
1802 # "enum packet_type".
1803 def get_enum_packet(packets):
1804 intro="enum packet_type {\n"
1806 mapping={}
1807 for p in packets:
1808 if p.type_number in mapping :
1809 print(p.name,mapping[p.type_number].name)
1810 assert 0
1811 mapping[p.type_number]=p
1812 sorted=list(mapping.keys())
1813 sorted.sort()
1815 last=-1
1816 body=""
1817 for i in sorted:
1818 p=mapping[i]
1819 if i!=last+1:
1820 line=" %s = %d,"%(p.type,i)
1821 else:
1822 line=" %s,"%(p.type)
1824 if (i%10)==0:
1825 line="%-40s /* %d */"%(line,i)
1826 body=body+line+"\n"
1828 last=i
1829 extro='''
1830 PACKET_LAST /* leave this last */
1834 return intro+body+extro
1836 def strip_c_comment(s):
1837 # The obvious way:
1838 # s=re.sub(r"/\*(.|\n)*?\*/","",s)
1839 # doesn't work with python version 2.2 and 2.3.
1840 # Do it by hand then.
1841 result=""
1842 for i in filter(lambda x:x,s.split("/*")):
1843 l=i.split("*/",1)
1844 assert len(l)==2,repr(i)
1845 result=result+l[1]
1846 return result
1848 # Main function. It reads and parses the input and generates the
1849 # various files.
1850 def main():
1851 ### parsing input
1852 src_dir=os.path.dirname(sys.argv[0])
1853 src_root=src_dir+"/.."
1854 input_name=src_dir+"/networking/packets.def"
1855 ### We call this variable target_root instead of build_root
1856 ### to avoid confusion as we are not building to builddir in
1857 ### automake sense.
1858 ### We build to src dir. Building to builddir causes a lot
1859 ### of problems we have been unable to solve.
1860 target_root=src_root
1862 content=open(input_name).read()
1863 content=strip_c_comment(content)
1864 lines=content.split("\n")
1865 lines=map(lambda x: re.sub("\s*#.*$","",x),lines)
1866 lines=map(lambda x: re.sub("\s*//.*$","",x),lines)
1867 lines=filter(lambda x:not re.search("^\s*$",x),lines)
1868 lines2=[]
1869 types=[]
1870 for i in lines:
1871 mo=re.search("^type\s+(\S+)\s*=\s*(.+)\s*$",i)
1872 if mo:
1873 types.append(Type(mo.group(1),mo.group(2)))
1874 else:
1875 lines2.append(i)
1877 packets=[]
1878 for str in re.split("(?m)^end$","\n".join(lines2)):
1879 str=str.strip()
1880 if str:
1881 packets.append(Packet(str,types))
1883 ### parsing finished
1885 ### writing packets_gen.h
1886 output_h_name=target_root+"/common/packets_gen.h"
1888 if lazy_overwrite:
1889 output_h=fc_open(output_h_name+".tmp")
1890 else:
1891 output_h=fc_open(output_h_name)
1893 output_h.write('''
1894 #ifdef __cplusplus
1895 extern "C" {
1896 #endif /* __cplusplus */
1898 /* common */
1899 #include "actions.h"
1900 #include "disaster.h"
1902 ''')
1904 # write structs
1905 for p in packets:
1906 output_h.write(p.get_struct())
1908 output_h.write(get_enum_packet(packets))
1910 # write function prototypes
1911 for p in packets:
1912 output_h.write(p.get_prototypes())
1913 output_h.write('''
1914 void delta_stats_report(void);
1915 void delta_stats_reset(void);
1917 #ifdef __cplusplus
1919 #endif /* __cplusplus */
1920 ''')
1921 output_h.close()
1923 ### writing packets_gen.c
1924 output_c_name=target_root+"/common/packets_gen.c"
1925 if lazy_overwrite:
1926 output_c=fc_open(output_c_name+".tmp")
1927 else:
1928 output_c=fc_open(output_c_name)
1930 output_c.write('''
1931 #ifdef HAVE_CONFIG_H
1932 #include <fc_config.h>
1933 #endif
1935 #include <string.h>
1937 /* utility */
1938 #include "bitvector.h"
1939 #include "capability.h"
1940 #include "genhash.h"
1941 #include "log.h"
1942 #include "mem.h"
1943 #include "support.h"
1945 /* common */
1946 #include "capstr.h"
1947 #include "connection.h"
1948 #include "dataio.h"
1949 #include "game.h"
1951 #include "packets.h"
1952 ''')
1953 output_c.write(get_packet_functional_capability(packets))
1954 output_c.write('''
1955 #ifdef FREECIV_DELTA_PROTOCOL
1956 static genhash_val_t hash_const(const void *vkey)
1958 return 0;
1961 static bool cmp_const(const void *vkey1, const void *vkey2)
1963 return TRUE;
1965 #endif /* FREECIV_DELTA_PROTOCOL */
1966 ''')
1968 if generate_stats:
1969 output_c.write('''
1970 static int stats_total_sent;
1972 ''')
1974 if generate_stats:
1975 # write stats
1976 for p in packets:
1977 output_c.write(p.get_stats())
1978 # write report()
1979 output_c.write(get_report(packets))
1980 output_c.write(get_reset(packets))
1982 output_c.write(get_packet_name(packets))
1983 output_c.write(get_packet_has_game_info_flag(packets))
1985 # write hash, cmp, send, receive
1986 for p in packets:
1987 output_c.write(p.get_variants())
1988 output_c.write(p.get_send())
1989 output_c.write(p.get_lsend())
1990 output_c.write(p.get_dsend())
1991 output_c.write(p.get_dlsend())
1993 output_c.write(get_packet_handlers_fill_initial(packets))
1994 output_c.write(get_packet_handlers_fill_capability(packets))
1995 output_c.close()
1997 if lazy_overwrite:
1998 for i in [output_h_name,output_c_name]:
1999 if os.path.isfile(i):
2000 old=open(i).read()
2001 else:
2002 old=""
2003 new=open(i+".tmp").read()
2004 if old!=new:
2005 open(i,"w").write(new)
2006 os.remove(i+".tmp")
2008 f=fc_open(target_root+"/server/hand_gen.h")
2009 f.write('''
2010 #ifndef FC__HAND_GEN_H
2011 #define FC__HAND_GEN_H
2013 /* utility */
2014 #include "shared.h"
2016 /* common */
2017 #include "fc_types.h"
2018 #include "packets.h"
2020 struct connection;
2022 bool server_handle_packet(enum packet_type type, const void *packet,
2023 struct player *pplayer, struct connection *pconn);
2025 ''')
2027 for p in packets:
2028 if "cs" in p.dirs and not p.no_handle:
2029 a=p.name[len("packet_"):]
2030 type=a.split("_")[0]
2031 b=p.fields
2032 b=map(lambda x:"%s%s"%(x.get_handle_type(), x.name),b)
2033 b=", ".join(b)
2034 if b:
2035 b=", "+b
2036 if p.handle_via_packet:
2037 f.write('struct %s;\n'%p.name)
2038 if p.handle_per_conn:
2039 f.write('void handle_%s(struct connection *pc, const struct %s *packet);\n'%(a,p.name))
2040 else:
2041 f.write('void handle_%s(struct player *pplayer, const struct %s *packet);\n'%(a,p.name))
2042 else:
2043 if p.handle_per_conn:
2044 f.write('void handle_%s(struct connection *pc%s);\n'%(a,b))
2045 else:
2046 f.write('void handle_%s(struct player *pplayer%s);\n'%(a,b))
2047 f.write('''
2048 #endif /* FC__HAND_GEN_H */
2049 ''')
2050 f.close()
2052 f=fc_open(target_root+"/client/packhand_gen.h")
2053 f.write('''
2054 #ifndef FC__PACKHAND_GEN_H
2055 #define FC__PACKHAND_GEN_H
2057 #ifdef __cplusplus
2058 extern "C" {
2059 #endif /* __cplusplus */
2061 /* utility */
2062 #include "shared.h"
2064 /* common */
2065 #include "packets.h"
2067 bool client_handle_packet(enum packet_type type, const void *packet);
2069 ''')
2070 for p in packets:
2071 if "sc" not in p.dirs: continue
2073 a=p.name[len("packet_"):]
2074 b=p.fields
2075 #print len(p.fields),p.name
2076 b=map(lambda x:"%s%s"%(x.get_handle_type(), x.name),b)
2077 b=", ".join(b)
2078 if not b:
2079 b="void"
2080 if p.handle_via_packet:
2081 f.write('struct %s;\n'%p.name)
2082 f.write('void handle_%s(const struct %s *packet);\n'%(a,p.name))
2083 else:
2084 f.write('void handle_%s(%s);\n'%(a,b))
2085 f.write('''
2086 #ifdef __cplusplus
2088 #endif /* __cplusplus */
2090 #endif /* FC__PACKHAND_GEN_H */
2091 ''')
2092 f.close()
2094 f=fc_open(target_root+"/server/hand_gen.c")
2095 f.write('''
2097 #ifdef HAVE_CONFIG_H
2098 #include <fc_config.h>
2099 #endif
2101 /* common */
2102 #include "packets.h"
2104 #include "hand_gen.h"
2106 bool server_handle_packet(enum packet_type type, const void *packet,
2107 struct player *pplayer, struct connection *pconn)
2109 switch(type) {
2110 ''')
2111 for p in packets:
2112 if "cs" not in p.dirs: continue
2113 if p.no_handle: continue
2114 a=p.name[len("packet_"):]
2115 c='((const struct %s *)packet)->'%p.name
2116 b=[]
2117 for x in p.fields:
2118 y="%s%s"%(c,x.name)
2119 if x.dataio_type=="worklist":
2120 y="&"+y
2121 b.append(y)
2122 b=",\n ".join(b)
2123 if b:
2124 b=",\n "+b
2126 if p.handle_via_packet:
2127 if p.handle_per_conn:
2128 args="pconn, packet"
2129 else:
2130 args="pplayer, packet"
2132 else:
2133 if p.handle_per_conn:
2134 args="pconn"+b
2135 else:
2136 args="pplayer"+b
2138 f.write(''' case %s:
2139 handle_%s(%s);
2140 return TRUE;
2142 '''%(p.type,a,args))
2143 f.write(''' default:
2144 return FALSE;
2147 ''')
2148 f.close()
2150 f=fc_open(target_root+"/client/packhand_gen.c")
2151 f.write('''
2153 #ifdef HAVE_CONFIG_H
2154 #include <fc_config.h>
2155 #endif
2157 /* common */
2158 #include "packets.h"
2160 #include "packhand_gen.h"
2162 bool client_handle_packet(enum packet_type type, const void *packet)
2164 switch(type) {
2165 ''')
2166 for p in packets:
2167 if "sc" not in p.dirs: continue
2168 if p.no_handle: continue
2169 a=p.name[len("packet_"):]
2170 c='((const struct %s *)packet)->'%p.name
2171 b=[]
2172 for x in p.fields:
2173 y="%s%s"%(c,x.name)
2174 if x.dataio_type=="worklist":
2175 y="&"+y
2176 b.append(y)
2177 b=",\n ".join(b)
2178 if b:
2179 b="\n "+b
2181 if p.handle_via_packet:
2182 args="packet"
2183 else:
2184 args=b
2186 f.write(''' case %s:
2187 handle_%s(%s);
2188 return TRUE;
2190 '''%(p.type,a,args))
2191 f.write(''' default:
2192 return FALSE;
2195 ''')
2196 f.close()
2198 main()