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)
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.
23 # generate_logs will generate log calls to debug the delta code.
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
45 def prefix(prefix
,str):
47 lines
=map(lambda x
,prefix
=prefix
: prefix
+x
,lines
)
48 return "\n".join(lines
)
50 def write_disclaimer(f
):
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 ****************************************************************************/
62 verbose("writing %s"%name
)
68 def helper(helper
,all
, index
, 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
)
80 def without(all
,part
):
87 # A simple container for a type alias
89 def __init__(self
,alias
,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)
100 for i
in mo
.groups():
102 arr
.append(i
.strip())
105 type,fields_
,flags
=arr
120 mo
=re
.search("^(.*)\((.*)\)$",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"])
127 typeinfo
["dataio_type"]=mo
.group(1)
128 typeinfo
["float_factor"]=int(mo
.group(2))
132 for i
in fields_
.split(","):
142 arr
.append("old->"+arr
[1])
143 arr
[1]="real_packet->"+arr
[1]
146 mo
=re
.search(r
"^(.*)\[(.*)\]\[(.*)\]$",i
)
148 t
["name"]=mo
.group(1)
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))
153 mo
=re
.search(r
"^(.*)\[(.*)\]$",i
)
155 t
["name"]=mo
.group(1)
157 t
["array_size_d"],t
["array_size_u"],t
["array_size_o"]=f(mo
.group(2))
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")
175 mo
=re
.search("^add-cap\((.*)\)$",i
)
177 adds
.append(mo
.group(1))
179 mo
=re
.search("^remove-cap\((.*)\)$",i
)
181 removes
.append(mo
.group(1))
185 assert len(arr
)==0,repr(arr
)
186 assert len(adds
)+len(removes
) in [0,1]
189 flaginfo
["add_cap"]=adds
[0]
191 flaginfo
["add_cap"]=""
194 flaginfo
["remove_cap"]=removes
[0]
196 flaginfo
["remove_cap"]=""
198 #print typeinfo,flaginfo,fields
201 result
.append(Field(f
,typeinfo
,flaginfo
))
204 # Class for a field (part of a packet). It has a name, serveral types,
205 # flags and some other attributes.
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
214 def get_dict(self
,vars):
215 result
=self
.__dict
__.copy()
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
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
230 def get_declar(self
):
232 return "%(struct_type)s %(name)s[%(array_size1_d)s][%(array_size2_d)s]"%self
.__dict
__
234 return "%(struct_type)s %(name)s[%(array_size_d)s]"%self
.__dict
__
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.
241 if self
.dataio_type
=="worklist":
242 return " worklist_copy(&real_packet->%(name)s, %(name)s);"%self
.__dict
__
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
__
248 tmp
="real_packet->%(name)s[i] = %(name)s[i]"%self
.__dict
__
252 for (i = 0; i < %(array_size_u) s; i++) {
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".
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
278 c
="!are_%(dataio_type)ss_equal(&old->%(name)s[i], &real_packet->%(name)s[i])"%self
.__dict
__
280 c
="old->%(name)s[i] != real_packet->%(name)s[i]"%self
.__dict
__
284 differ = (%(array_size_o)s != %(array_size_u)s);
287 for (i = 0; i < %(array_size_u)s; i++) {
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
300 def get_cmp_wrapper(self
,i
):
302 if fold_bool_into_header
and self
.struct_type
=="bool" and \
304 b
="packet->%(name)s"%self
.get_dict(vars())
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 \
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
333 f
=' %(log_macro)s(" field \'%(name)s\' has changed");\n'%self
.get_dict(vars())
337 s
=' stats_%(packet_name)s_counters[%(i)d]++;\n'%self
.get_dict(vars())
340 return ''' if (BV_ISSET(fields, %(i)d)) {
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 */
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
__
374 c
="DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s[i][j]);"%self
.__dict
__
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":
383 c
=" DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i][j], %(float_factor)d);"%self
.__dict
__
385 c
=" DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i], %(float_factor)d);"%self
.__dict
__
388 c
="DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i][j]);"%self
.__dict
__
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:
397 #ifdef FREECIV_JSON_CONNECTION
400 for (i = 0; i < %(array_size_u)s; i++) {
401 if (old->%(name)s[i] != real_packet->%(name)s[i]) {
405 /* Create the array. */
406 DIO_PUT(farray, &dout, &field_addr, count + 1);
409 field_addr.sub_location = plocation_elem_new(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 */
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;
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":
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 */
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())
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 */
532 #ifdef FREECIV_JSON_CONNECTION
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 \
545 return " real_packet->%(name)s = BV_ISSET(fields, %(i)d);\n"%self
.get_dict(vars())
547 log_macro
=packet
.log_macro
549 f
=" %(log_macro)s(\" got field '%(name)s'\");\n"%self
.get_dict(vars())
552 return ''' if (BV_ISSET(fields, %(i)d)) {
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 */
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);
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);
575 if self
.dataio_type
in ["string","estring","city_map"] and \
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);
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);
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);
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);
597 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &readin)) {
598 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
600 real_packet->%(name)s = readin;
605 c
='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i][j])) {
606 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
609 c
='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i])) {
610 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
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);
616 elif self
.struct_type
=="float":
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);
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);
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);
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;
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);
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;
654 array_size_u
=self
.array_size1_u
655 array_size_d
=self
.array_size1_d
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
:
663 if (%(array_size_u)s > %(array_size_d)s) {
664 RECEIVE_PACKET_FIELD_ERROR(%(name)s, ": truncation array");
665 }'''%self
.get_dict(vars())
668 if self
.dataio_type
=="memory":
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":
679 #ifdef FREECIV_JSON_CONNECTION
680 /* Enter outer array. */
681 field_addr.sub_location = plocation_elem_new(0);
682 #endif /* FREECIV_JSON_CONNECTION */
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 */
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())
718 #ifdef FREECIV_JSON_CONNECTION
720 field_addr.sub_location = plocation_elem_new(0);
721 #endif /* FREECIV_JSON_CONNECTION */
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 */
730 #ifdef FREECIV_JSON_CONNECTION
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:
741 #ifdef FREECIV_JSON_CONNECTION
743 field_addr.sub_location = plocation_elem_new(0);
744 #endif /* FREECIV_JSON_CONNECTION */
746 for (count = 0;; count++) {
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);
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 */
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\",
778 #ifdef FREECIV_JSON_CONNECTION
779 /* Content address. */
780 field_addr.sub_location->sub_location->number = 1;
781 #endif /* FREECIV_JSON_CONNECTION */
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
794 free(field_addr.sub_location);
795 field_addr.sub_location = NULL;
796 #endif /* FREECIV_JSON_CONNECTION */
797 }'''%self
.get_dict(vars())
803 for (i = 0; i < %(array_size_u)s; i++) {
806 }'''%self
.get_dict(vars())
809 # Class which represents a capability 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
816 self
.packet_name
=packet
.name
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
832 if self
.poscaps
or self
.negcaps
:
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
)
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
,
847 self
.keys_arg
=",\n "+self
.keys_arg
849 if len(self
.fields
)==0:
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
),
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
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
__
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
__
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
__
886 def get_dict(self
,vars):
887 result
=self
.__dict
__.copy()
891 # Returns a code fragment which contains the declarations of the
892 # statistical counters of this packet.
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
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
):
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]);
929 # Returns a code fragment which is the packet specific part of
930 # the delta_stats_reset() function.
931 def get_reset_part(self
):
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));
939 # Returns a code fragment which is the implementation of the hash
940 # function. The hash function is using all key fields.
942 if len(self
.key_fields
)==0:
943 return "#define hash_%(name)s hash_const\n\n"%self
.__dict
__
945 intro
='''static genhash_val_t hash_%(name)s(const void *vkey)
949 body
=''' const struct %(packet_name)s *key = (const struct %(packet_name)s *) vkey;
953 keys
=list(map(lambda x
:"key->"+x
.name
,self
.key_fields
))
957 a
="(%s << 8) ^ %s"%(keys
[0], keys
[1])
960 body
=body
+(' return %s;\n'%a
)
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.
968 if len(self
.key_fields
)==0:
969 return "#define cmp_%(name)s cmp_const\n\n"%self
.__dict
__
971 intro
='''static bool cmp_%(name)s(const void *vkey1, const void *vkey2)
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;
979 for field
in self
.key_fields
:
980 body
=body
+''' return key1->%s == key2->%s;
981 '''%(field
.name
,field
.name
)
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
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);
999 stats_%(name)s_sent++;
1004 log
='\n %(log_macro)s("%(name)s: sending info about (%(keys_format)s)"%(keys_arg)s);\n'
1007 if self
.want_pre_send
:
1010 struct %(packet_name)s *tmp = fc_malloc(sizeof(*tmp));
1013 pre_send_%(packet_name)s(pc, tmp);
1018 if (real_packet != packet) {
1019 free((void *) real_packet);
1026 if not self
.no_packet
:
1027 real_packet1
=" const struct %(packet_name)s *real_packet = packet;\n"
1031 if not self
.no_packet
:
1034 diff
='force_to_send'
1037 delta_header
='''#ifdef FREECIV_DELTA_PROTOCOL
1038 %(name)s_fields fields;
1039 struct %(packet_name)s *old;
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"
1048 body
="#if 1 /* To match endif */"
1050 for field
in self
.fields
:
1051 body
=body
+field
.get_put(0)+"\n"
1052 body
=body
+"\n#endif\n"
1057 if self
.want_post_send
:
1059 post
=" post_send_%(packet_name)s(pc, NULL);\n"
1061 post
=" post_send_%(packet_name)s(pc, real_packet);\n"
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 */
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())
1081 # Helper for get_send()
1082 def get_delta_send_body(self
):
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);
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. */
1100 for i
in range(len(self
.other_fields
)):
1101 field
=self
.other_fields
[i
]
1102 body
=body
+field
.get_cmp_wrapper(i
)
1104 fl
=' %(log_macro)s(" no change -> discard");\n'
1108 s
=' stats_%(name)s_discarded++;\n'
1112 if self
.is_info
!= "no":
1114 if (different == 0) {
1115 %(fl)s%(s)s<pre2> return 0;
1117 '''%self
.get_dict(vars())
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"
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)
1134 *old = *real_packet;
1137 # Cancel some is-info packets.
1138 for i
in self
.cancel
:
1140 hash = pc->phs.sent + %s;
1141 if (NULL != *hash) {
1142 genhash_remove(*hash, real_packet);
1145 body
=body
+'''#endif /* FREECIV_DELTA_PROTOCOL */'''
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);
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 */
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);
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()
1182 body1
="#if 1 /* To match endif */\n"
1185 for field
in self
.fields
:
1186 nondelta
=nondelta
+prefix(" ",field
.get_get(0))+"\n"
1188 nondelta
=" real_packet->__dummy = 0xff;"
1189 body1
=body1
+nondelta
+"\n#endif\n"
1192 log
=' %(log_macro)s("%(name)s: got info about (%(keys_format)s)"%(keys_arg)s);\n'
1196 if self
.want_post_recv
:
1197 post
=" post_receive_%(packet_name)s(pc, real_packet);\n"
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 */
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
1224 fl
=' %(log_macro)s(" no old info");\n'
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;
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)
1247 old = fc_malloc(sizeof(*old));
1248 *old = *real_packet;
1249 genhash_insert(*hash, old, old);
1251 *old = *real_packet;
1253 '''%self
.get_dict(vars())
1255 # Cancel some is-info packets.
1256 for i
in self
.cancel
:
1258 hash = pc->phs.received + %s;
1259 if (NULL != *hash) {
1260 genhash_remove(*hash, real_packet);
1264 return body
+extro
+'''
1265 #endif /* FREECIV_DELTA_PROTOCOL */
1268 # Class which represents a packet. A packet contains a list of fields.
1270 def __init__(self
,str, types
):
1272 self
.log_macro
=use_log_macro
1273 self
.gen_stats
=generate_stats
1274 self
.gen_log
=generate_logs
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
1289 arr
=list(item
.strip() for item
in dummy
.split(",") if item
)
1294 self
.dirs
.append("sc")
1297 self
.dirs
.append("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
1305 if "is-info" in arr
:
1307 arr
.remove("is-info")
1308 if "is-game-info" in arr
:
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")
1349 mo
=re
.search("^cancel\((.*)\)$",i
)
1351 self
.cancel
.append(mo
.group(1))
1356 assert len(arr
)==0,repr(arr
)
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
,
1368 self
.keys_arg
=",\n "+self
.keys_arg
1371 self
.want_dsend
=self
.dsend_given
1373 if len(self
.fields
)==0:
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
),
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
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
__
1400 self
.lsend_prototype
='void lsend_%(name)s(struct conn_list *dest%(extra_send_args)s)'%self
.__dict
__
1402 self
.dsend_prototype
='int dsend_%(name)s(struct connection *pc%(extra_send_args3)s)'%self
.__dict
__
1404 self
.dlsend_prototype
='void dlsend_%(name)s(struct conn_list *dest%(extra_send_args3)s)'%self
.__dict
__
1406 # create cap variants
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
)
1415 for i
in range(len(choices
)):
1417 negcaps
=without(all_caps
,poscaps
)
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
)
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
__
1437 for field
in self
.key_fields
+self
.other_fields
:
1438 body
=body
+" %s;\n"%field
.get_declar()
1440 body
=" char __dummy; /* to avoid malloc(0); */\n"
1441 return intro
+body
+extro
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"
1449 result
=result
+self
.lsend_prototype
+";\n"
1451 result
=result
+self
.dsend_prototype
+";\n"
1453 result
=result
+self
.dlsend_prototype
+";\n"
1456 # See Field.get_dict
1457 def get_dict(self
,vars):
1458 result
=self
.__dict
__.copy()
1466 elif self
.want_force
:
1467 func
="force_to_send"
1468 args
=", packet, force_to_send"
1473 return '''%(send_prototype)s
1476 log_error("WARNING: trying to send data to the closed connection %%s",
1477 conn_description(pc));
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
):
1489 for v
in self
.variants
:
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()
1500 # Returns a code fragment which is the implementation of the
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;
1513 # Returns a code fragment which is the implementation of the
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;
1524 return send_%(name)s(pc, real_packet);
1527 '''%self
.get_dict(vars())
1529 # Returns a code fragment which is the implementation of the
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;
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
):
1551 if f
.add_cap
: all_caps
[f
.add_cap
]=1
1552 if f
.remove_cap
: all_caps
[f
.remove_cap
]=1
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'
1563 void delta_stats_report(void) {
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'
1579 void delta_stats_reset(void) {
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] = {
1598 mapping
[p
.type_number
]=p
1599 sorted=list(mapping
.keys())
1605 for i
in range(last
+ 1, n
):
1606 body
=body
+' "unknown",\n'
1607 body
=body
+' "%s",\n'%mapping
[n
].type
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] = {
1628 mapping
[p
.type_number
]=p
1629 sorted=list(mapping
.keys())
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
1640 body
=body
+' TRUE, /* %s */\n'%mapping
[n
].type
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)
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!");
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
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
)
1682 unrestricted
.append(p
)
1685 for p
in unrestricted
:
1686 body
=body
+''' %(send_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
__
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)
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
)
1730 unrestricted
.append(p
)
1733 for p
in unrestricted
:
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);
1740 } else '''%v
.__dict
__
1742 log_error("Unknown %(type)s variant for cap %%s", capability);
1745 if len(cs_packets
)>0 or len(sc_packets
)>0:
1746 body
=body
+''' if (is_server()) {
1748 for p
in sc_packets
:
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);
1754 } else '''%v
.__dict
__
1756 log_error("Unknown %(type)s variant for cap %%s", capability);
1759 for p
in cs_packets
:
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);
1765 } else '''%v
.__dict
__
1767 log_error("Unknown %(type)s variant for cap %%s", capability);
1770 body
=body
+''' } else {
1772 for p
in cs_packets
:
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);
1778 } else '''%v
.__dict
__
1780 log_error("Unknown %(type)s variant for cap %%s", capability);
1783 for p
in sc_packets
:
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);
1789 } else '''%v
.__dict
__
1791 log_error("Unknown %(type)s variant for cap %%s", capability);
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"
1808 if p
.type_number
in mapping
:
1809 print(p
.name
,mapping
[p
.type_number
].name
)
1811 mapping
[p
.type_number
]=p
1812 sorted=list(mapping
.keys())
1820 line
=" %s = %d,"%(p
.type,i
)
1822 line
=" %s,"%(p
.type)
1825 line
="%-40s /* %d */"%(line
,i
)
1830 PACKET_LAST /* leave this last */
1834 return intro
+body
+extro
1836 def strip_c_comment(s
):
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.
1842 for i
in filter(lambda x
:x
,s
.split("/*")):
1844 assert len(l
)==2,repr(i
)
1848 # Main function. It reads and parses the input and generates the
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
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
)
1871 mo
=re
.search("^type\s+(\S+)\s*=\s*(.+)\s*$",i
)
1873 types
.append(Type(mo
.group(1),mo
.group(2)))
1878 for str in re
.split("(?m)^end$","\n".join(lines2
)):
1881 packets
.append(Packet(str,types
))
1883 ### parsing finished
1885 ### writing packets_gen.h
1886 output_h_name
=target_root
+"/common/packets_gen.h"
1889 output_h
=fc_open(output_h_name
+".tmp")
1891 output_h
=fc_open(output_h_name
)
1896 #endif /* __cplusplus */
1899 #include "actions.h"
1900 #include "disaster.h"
1906 output_h
.write(p
.get_struct())
1908 output_h
.write(get_enum_packet(packets
))
1910 # write function prototypes
1912 output_h
.write(p
.get_prototypes())
1914 void delta_stats_report(void);
1915 void delta_stats_reset(void);
1919 #endif /* __cplusplus */
1923 ### writing packets_gen.c
1924 output_c_name
=target_root
+"/common/packets_gen.c"
1926 output_c
=fc_open(output_c_name
+".tmp")
1928 output_c
=fc_open(output_c_name
)
1931 #ifdef HAVE_CONFIG_H
1932 #include <fc_config.h>
1938 #include "bitvector.h"
1939 #include "capability.h"
1940 #include "genhash.h"
1943 #include "support.h"
1947 #include "connection.h"
1951 #include "packets.h"
1953 output_c
.write(get_packet_functional_capability(packets
))
1955 #ifdef FREECIV_DELTA_PROTOCOL
1956 static genhash_val_t hash_const(const void *vkey)
1961 static bool cmp_const(const void *vkey1, const void *vkey2)
1965 #endif /* FREECIV_DELTA_PROTOCOL */
1970 static int stats_total_sent;
1977 output_c
.write(p
.get_stats())
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
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
))
1998 for i
in [output_h_name
,output_c_name
]:
1999 if os
.path
.isfile(i
):
2003 new
=open(i
+".tmp").read()
2005 open(i
,"w").write(new
)
2008 f
=fc_open(target_root
+"/server/hand_gen.h")
2010 #ifndef FC__HAND_GEN_H
2011 #define FC__HAND_GEN_H
2017 #include "fc_types.h"
2018 #include "packets.h"
2022 bool server_handle_packet(enum packet_type type, const void *packet,
2023 struct player *pplayer, struct connection *pconn);
2028 if "cs" in p
.dirs
and not p
.no_handle
:
2029 a
=p
.name
[len("packet_"):]
2030 type=a
.split("_")[0]
2032 b
=map(lambda x
:"%s%s"%(x
.get_handle_type(), x
.name
),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
))
2041 f
.write('void handle_%s(struct player *pplayer, const struct %s *packet);\n'%(a
,p
.name
))
2043 if p
.handle_per_conn
:
2044 f
.write('void handle_%s(struct connection *pc%s);\n'%(a
,b
))
2046 f
.write('void handle_%s(struct player *pplayer%s);\n'%(a
,b
))
2048 #endif /* FC__HAND_GEN_H */
2052 f
=fc_open(target_root
+"/client/packhand_gen.h")
2054 #ifndef FC__PACKHAND_GEN_H
2055 #define FC__PACKHAND_GEN_H
2059 #endif /* __cplusplus */
2065 #include "packets.h"
2067 bool client_handle_packet(enum packet_type type, const void *packet);
2071 if "sc" not in p
.dirs
: continue
2073 a
=p
.name
[len("packet_"):]
2075 #print len(p.fields),p.name
2076 b
=map(lambda x
:"%s%s"%(x
.get_handle_type(), x
.name
),b
)
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
))
2084 f
.write('void handle_%s(%s);\n'%(a
,b
))
2088 #endif /* __cplusplus */
2090 #endif /* FC__PACKHAND_GEN_H */
2094 f
=fc_open(target_root
+"/server/hand_gen.c")
2097 #ifdef HAVE_CONFIG_H
2098 #include <fc_config.h>
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)
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
2119 if x
.dataio_type
=="worklist":
2126 if p
.handle_via_packet
:
2127 if p
.handle_per_conn
:
2128 args
="pconn, packet"
2130 args
="pplayer, packet"
2133 if p
.handle_per_conn
:
2138 f
.write(''' case %s:
2142 '''%(p
.type,a
,args
))
2143 f
.write(''' default:
2150 f
=fc_open(target_root
+"/client/packhand_gen.c")
2153 #ifdef HAVE_CONFIG_H
2154 #include <fc_config.h>
2158 #include "packets.h"
2160 #include "packhand_gen.h"
2162 bool client_handle_packet(enum packet_type type, const void *packet)
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
2174 if x
.dataio_type
=="worklist":
2181 if p
.handle_via_packet
:
2186 f
.write(''' case %s:
2190 '''%(p
.type,a
,args
))
2191 f
.write(''' default: