Freeciv-3.1
Loading...
Searching...
No Matches
generate_packets.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3#
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.
9#
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.
14#
15
16
17
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.
21generate_stats=0
22
23# generate_logs will generate log calls to debug the delta code.
24generate_logs=1
25use_log_macro="log_packet_detailed"
26generate_variant_logs=1
27
28
29fold_bool_into_header=1
30
31
32
33# This script runs under Python 3.4 and up. Please leave it so.
34# It might also run under older versions, but no such guarantees are made.
35
36import re, string, os, sys
37
38lazy_overwrite=0
39
40def verbose(s):
41 if "-v" in sys.argv:
42 print(s)
43
44def prefix(prefix,str):
45 lines=str.split("\n")
46 lines=map(lambda x,prefix=prefix: prefix+x,lines)
47 return "\n".join(lines)
48
50 f.write('''
51 /****************************************************************************
52 * THIS FILE WAS GENERATED *
53 * Script: common/generate_packets.py *
54 * Input: common/networking/packets.def *
55 * DO NOT CHANGE THIS FILE *
56 ****************************************************************************/
57
58''')
59
60def fc_open(name):
61 verbose("writing %s"%name)
62 f=open(name,"w")
64 return f
65
66def get_choices(all):
67 def helper(helper,all, index, so_far):
68 if index>=len(all):
69 return [so_far]
70 t0=so_far[:]
71 t1=so_far[:]
72 t1.append(list(all)[index])
73 return helper(helper,all,index+1,t1)+helper(helper,all,index+1,t0)
74
75 result=helper(helper,all,0,[])
76 assert len(result)==2**len(all)
77 return result
78
79def without(all,part):
80 result=[]
81 for i in all:
82 if i not in part:
83 result.append(i)
84 return result
85
86# A simple container for a type alias
87class Type:
88 def __init__(self,alias,dest):
89 self.alias=alias
90 self.dest=dest
91
92# Parses a line of the form "COORD x, y; key" and returns a list of
93# Field objects. types is a list of Type objects which are used to
94# dereference type names.
95def parse_fields(str, types):
96 mo=re.search(r"^\s*(\S+(?:\‍(.*\‍))?)\s+([^;()]*)\s*;\s*(.*)\s*$",str)
97 assert mo,str
98 arr=[]
99 for i in mo.groups():
100 if i:
101 arr.append(i.strip())
102 else:
103 arr.append("")
104 type,fields_,flags=arr
105 #print arr
106
107 # analyze type
108 while 1:
109 found=0
110 for i in types:
111 if i.alias==type:
112 type=i.dest
113 found=1
114 break
115 if not found:
116 break
117
118 typeinfo={}
119 mo = re.search(r"^(.*)\‍((.*)\‍)$", type)
120 assert mo,repr(type)
121 typeinfo["dataio_type"],typeinfo["struct_type"]=mo.groups()
122
123 if typeinfo["struct_type"]=="float":
124 mo = re.search(r"^(\D+)(\d+)$", typeinfo["dataio_type"])
125 assert mo
126 typeinfo["dataio_type"]=mo.group(1)
127 typeinfo["float_factor"]=int(mo.group(2))
128
129 # analyze fields
130 fields=[]
131 for i in fields_.split(","):
132 i=i.strip()
133 t={}
134
135 def f(x):
136 arr=x.split(":")
137 if len(arr)==1:
138 return [x,x,x]
139 else:
140 assert len(arr)==2
141 arr.append("old->"+arr[1])
142 arr[1]="real_packet->"+arr[1]
143 return arr
144
145 mo=re.search(r"^(.*)\[(.*)\]\[(.*)\]$",i)
146 if mo:
147 t["name"]=mo.group(1)
148 t["is_array"]=2
149 t["array_size1_d"],t["array_size1_u"],t["array_size1_o"]=f(mo.group(2))
150 t["array_size2_d"],t["array_size2_u"],t["array_size2_o"]=f(mo.group(3))
151 else:
152 mo=re.search(r"^(.*)\[(.*)\]$",i)
153 if mo:
154 t["name"]=mo.group(1)
155 t["is_array"]=1
156 t["array_size_d"],t["array_size_u"],t["array_size_o"]=f(mo.group(2))
157 else:
158 t["name"]=i
159 t["is_array"]=0
160 fields.append(t)
161
162 # analyze flags
163 flaginfo={}
164 arr=list(item.strip() for item in flags.split(","))
165 arr=list(filter(lambda x:len(x)>0,arr))
166 flaginfo["is_key"]=("key" in arr)
167 if flaginfo["is_key"]: arr.remove("key")
168 flaginfo["diff"]=("diff" in arr)
169 if flaginfo["diff"]: arr.remove("diff")
170 adds=[]
171 removes=[]
172 remaining=[]
173 for i in arr:
174 mo = re.search(r"^add-cap\‍((.*)\‍)$", i)
175 if mo:
176 adds.append(mo.group(1))
177 continue
178 mo = re.search(r"^remove-cap\‍((.*)\‍)$", i)
179 if mo:
180 removes.append(mo.group(1))
181 continue
182 remaining.append(i)
183 arr=remaining
184 assert len(arr)==0,repr(arr)
185 assert len(adds)+len(removes) in [0,1]
186
187 if adds:
188 flaginfo["add_cap"]=adds[0]
189 else:
190 flaginfo["add_cap"]=""
191
192 if removes:
193 flaginfo["remove_cap"]=removes[0]
194 else:
195 flaginfo["remove_cap"]=""
196
197 #print typeinfo,flaginfo,fields
198 result=[]
199 for f in fields:
200 result.append(Field(f,typeinfo,flaginfo))
201 return result
202
203# Class for a field (part of a packet). It has a name, serveral types,
204# flags and some other attributes.
205class Field:
206 def __init__(self,fieldinfo,typeinfo,flaginfo):
207 for i in fieldinfo,typeinfo,flaginfo:
208 self.__dict__.update(i)
209 self.is_struct=not not re.search("^struct.*",self.struct_type)
210
211 # Helper function for the dictionary variant of the % operator
212 # ("%(name)s"%dict).
213 def get_dict(self,vars):
214 result=self.__dict__.copy()
215 result.update(vars)
216 return result
217
219 if self.dataio_type=="string" or self.dataio_type=="estring":
220 return "const char *"
221 if self.dataio_type=="worklist":
222 return "const %s *"%self.struct_type
223 if self.is_array:
224 return "const %s *"%self.struct_type
225 return self.struct_type+" "
226
227 # Returns code which is used in the declaration of the field in
228 # the packet struct.
229 def get_declar(self):
230 if self.is_array==2:
231 return "%(struct_type)s %(name)s[%(array_size1_d)s][%(array_size2_d)s]"%self.__dict__
232 if self.is_array:
233 return "%(struct_type)s %(name)s[%(array_size_d)s]"%self.__dict__
234 else:
235 return "%(struct_type)s %(name)s"%self.__dict__
236
237 # Returns code which copies the arguments of the direct send
238 # functions in the packet struct.
239 def get_fill(self):
240 if self.dataio_type=="worklist":
241 return " worklist_copy(&real_packet->%(name)s, %(name)s);"%self.__dict__
242 if self.is_array==0:
243 return " real_packet->%(name)s = %(name)s;"%self.__dict__
244 if self.dataio_type=="string" or self.dataio_type=="estring":
245 return " sz_strlcpy(real_packet->%(name)s, %(name)s);"%self.__dict__
246 if self.is_array==1:
247 tmp="real_packet->%(name)s[i] = %(name)s[i]"%self.__dict__
248 return ''' {
249 int i;
250
251 for (i = 0; i < %(array_size_u) s; i++) {
252 %(tmp)s;
253 }
254 }'''%self.get_dict(vars())
255
256 return repr(self.__dict__)
257
258 # Returns code which sets "differ" by comparing the field
259 # instances of "old" and "readl_packet".
260 def get_cmp(self):
261 if self.dataio_type=="memory":
262 return " differ = (memcmp(old->%(name)s, real_packet->%(name)s, %(array_size_d)s) != 0);"%self.__dict__
263 if self.dataio_type=="bitvector":
264 return " differ = !BV_ARE_EQUAL(old->%(name)s, real_packet->%(name)s);"%self.__dict__
265 if self.dataio_type in ["string", "estring"] and self.is_array==1:
266 return " differ = (strcmp(old->%(name)s, real_packet->%(name)s) != 0);"%self.__dict__
267 if self.dataio_type == "cm_parameter":
268 return " differ = !cm_are_parameter_equal(&old->%(name)s, &real_packet->%(name)s);" % self.__dict__
269 if self.is_struct and self.is_array==0:
270 return " differ = !are_%(dataio_type)ss_equal(&old->%(name)s, &real_packet->%(name)s);"%self.__dict__
271 if not self.is_array:
272 return " differ = (old->%(name)s != real_packet->%(name)s);"%self.__dict__
273
274 if self.dataio_type=="string" or self.dataio_type=="estring":
275 c="strcmp(old->%(name)s[i], real_packet->%(name)s[i]) != 0"%self.__dict__
276 array_size_u=self.array_size1_u
277 array_size_o=self.array_size1_o
278 elif self.is_struct:
279 c="!are_%(dataio_type)ss_equal(&old->%(name)s[i], &real_packet->%(name)s[i])"%self.__dict__
280 array_size_u = self.array_size_u
281 array_size_o = self.array_size_o
282 else:
283 c="old->%(name)s[i] != real_packet->%(name)s[i]"%self.__dict__
284 array_size_u = self.array_size_u
285 array_size_o = self.array_size_o
286
287 if array_size_u != array_size_o:
288 head = '''
289 {
290 differ = (%(array_size_o)s != %(array_size_u)s);
291 if (!differ) {''' % self.get_dict(vars())
292 else:
293 head = '''
294 {
295 differ = FALSE;
296 {'''
297 return head + '''
298 int i;
299
300 for (i = 0; i < %(array_size_u)s; i++) {
301 if (%(c)s) {
302 differ = TRUE;
303 break;
304 }
305 }
306 }
307 }'''%self.get_dict(vars())
308
309 @property
311 return (
312 fold_bool_into_header
313 and self.struct_type == "bool"
314 and not self.is_array
315 )
316
317 # Returns a code fragment which updates the bit of the this field
318 # in the "fields" bitvector. The bit is either a "content-differs"
319 # bit or (for bools which gets folded in the header) the actual
320 # value of the bool.
321 def get_cmp_wrapper(self, i, pack):
322 if self.folded_into_head:
323 if pack.is_info != "no":
324 cmp = self.get_cmp()
325 differ_part = '''
326 if (differ) {
327 different++;
328 }
329'''
330 else:
331 cmp = ''''''
332 differ_part = ''''''
333 b="packet->%(name)s"%self.get_dict(vars())
334 return '''%s'''%(cmp) + differ_part + ''' if (%s) {
335 BV_SET(fields, %d);
336 }
337
338'''%(b,i)
339 else:
340 cmp = self.get_cmp()
341 if pack.is_info != "no":
342 return '''%s
343 if (differ) {
344 different++;
345 BV_SET(fields, %d);
346 }
347
348'''%(cmp, i)
349 else:
350 return '''%s
351 if (differ) {
352 BV_SET(fields, %d);
353 }
354
355'''%(cmp, i)
356
357 # Returns a code fragment which will put this field if the
358 # content has changed. Does nothing for bools-in-header.
359 def get_put_wrapper(self,packet,i,deltafragment):
360 if fold_bool_into_header and self.struct_type=="bool" and \
361 not self.is_array:
362 return " /* field %(i)d is folded into the header */\n"%vars()
363 put=self.get_put(deltafragment)
364 packet_name=packet.name
365 log_macro=packet.log_macro
366 if packet.gen_log:
367 f=' %(log_macro)s(" field \'%(name)s\' has changed");\n'%self.get_dict(vars())
368 else:
369 f=""
370 if packet.gen_stats:
371 s=' stats_%(packet_name)s_counters[%(i)d]++;\n'%self.get_dict(vars())
372 else:
373 s=""
374 return ''' if (BV_ISSET(fields, %(i)d)) {
375%(f)s%(s)s %(put)s
376 }
377'''%self.get_dict(vars())
378
379 # Returns code which put this field.
380 def get_put(self,deltafragment):
381 return '''#ifdef FREECIV_JSON_CONNECTION
382 field_addr.name = \"%(name)s\";
383#endif /* FREECIV_JSON_CONNECTION */
384'''%self.__dict__ \
385 + self.get_put_real(deltafragment);
386
387 # The code which put this field before it is wrapped in address adding.
388 def get_put_real(self,deltafragment):
389 if self.dataio_type=="bitvector":
390 return "DIO_BV_PUT(&dout, &field_addr, packet->%(name)s);"%self.__dict__
391
392 if self.struct_type=="float" and not self.is_array:
393 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s, %(float_factor)d);"%self.__dict__
394
395 if self.dataio_type in ["worklist", "cm_parameter"]:
396 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s);"%self.__dict__
397
398 if self.dataio_type in ["memory"]:
399 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s, %(array_size_u)s);"%self.__dict__
400
401 arr_types=["string","estring","city_map"]
402 if (self.dataio_type in arr_types and self.is_array==1) or \
403 (self.dataio_type not in arr_types and self.is_array==0):
404 return " DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s);"%self.__dict__
405 if self.is_struct:
406 if self.is_array==2:
407 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s[i][j]);"%self.__dict__
408 else:
409 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, &real_packet->%(name)s[i]);"%self.__dict__
410 elif self.dataio_type=="string" or self.dataio_type=="estring":
411 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i]);"%self.__dict__
412 array_size_u=self.array_size1_u
413
414 elif self.struct_type=="float":
415 if self.is_array==2:
416 c=" DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i][j], %(float_factor)d);"%self.__dict__
417 else:
418 c=" DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i], %(float_factor)d);"%self.__dict__
419 else:
420 if self.is_array==2:
421 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i][j]);"%self.__dict__
422 else:
423 c="DIO_PUT(%(dataio_type)s, &dout, &field_addr, real_packet->%(name)s[i]);"%self.__dict__
424
425 if deltafragment and self.diff and self.is_array == 1:
426 return '''
427 {
428 int i;
429
430#ifdef FREECIV_JSON_CONNECTION
431 int count = 0;
432
433 for (i = 0; i < %(array_size_u)s; i++) {
434 if (old->%(name)s[i] != real_packet->%(name)s[i]) {
435 count++;
436 }
437 }
438 /* Create the array. */
439 DIO_PUT(farray, &dout, &field_addr, count + 1);
440
441 /* Enter array. */
442 field_addr.sub_location = plocation_elem_new(0);
443
444 count = 0;
445#endif /* FREECIV_JSON_CONNECTION */
446
447 fc_assert(%(array_size_u)s < 255);
448
449 for (i = 0; i < %(array_size_u)s; i++) {
450 if (old->%(name)s[i] != real_packet->%(name)s[i]) {
451#ifdef FREECIV_JSON_CONNECTION
452 /* Next diff array element. */
453 field_addr.sub_location->number = count - 1;
454
455 /* Create the diff array element. */
456 DIO_PUT(farray, &dout, &field_addr, 2);
457
458 /* Enter diff array element (start at the index address). */
459 field_addr.sub_location->sub_location = plocation_elem_new(0);
460#endif /* FREECIV_JSON_CONNECTION */
461 DIO_PUT(uint8, &dout, &field_addr, i);
462
463#ifdef FREECIV_JSON_CONNECTION
464 /* Content address. */
465 field_addr.sub_location->sub_location->number = 1;
466#endif /* FREECIV_JSON_CONNECTION */
467 %(c)s
468
469#ifdef FREECIV_JSON_CONNECTION
470 /* Exit diff array element. */
471 free(field_addr.sub_location->sub_location);
472 field_addr.sub_location->sub_location = NULL;
473#endif /* FREECIV_JSON_CONNECTION */
474 }
475 }
476#ifdef FREECIV_JSON_CONNECTION
477 field_addr.sub_location->number = count - 1;
478
479 /* Create the diff array element. */
480 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
481
482 /* Enter diff array element. Point to index address. */
483 field_addr.sub_location->sub_location = plocation_elem_new(0);
484#endif /* FREECIV_JSON_CONNECTION */
485 DIO_PUT(uint8, &dout, &field_addr, 255);
486
487#ifdef FREECIV_JSON_CONNECTION
488 /* Exit diff array element. */
489 free(field_addr.sub_location->sub_location);
490 field_addr.sub_location->sub_location = NULL;
491
492 /* Exit array. */
493 free(field_addr.sub_location);
494 field_addr.sub_location = NULL;
495#endif /* FREECIV_JSON_CONNECTION */
496 }'''%self.get_dict(vars())
497 if self.is_array == 2 and self.dataio_type != "string" \
498 and self.dataio_type != "estring":
499 return '''
500 {
501 int i, j;
502
503#ifdef FREECIV_JSON_CONNECTION
504 /* Create the outer array. */
505 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
506
507 /* Enter the outer array. */
508 field_addr.sub_location = plocation_elem_new(0);
509#endif /* FREECIV_JSON_CONNECTION */
510
511 for (i = 0; i < %(array_size1_u)s; i++) {
512#ifdef FREECIV_JSON_CONNECTION
513 /* Next inner array (an element in the outer array). */
514 field_addr.sub_location->number = i;
515
516 /* Create the inner array. */
517 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
518
519 /* Enter the inner array. */
520 field_addr.sub_location->sub_location = plocation_elem_new(0);
521#endif /* FREECIV_JSON_CONNECTION */
522
523 for (j = 0; j < %(array_size2_u)s; j++) {
524#ifdef FREECIV_JSON_CONNECTION
525 /* Next element (in the inner array). */
526 field_addr.sub_location->sub_location->number = j;
527#endif /* FREECIV_JSON_CONNECTION */
528 %(c)s
529 }
530
531#ifdef FREECIV_JSON_CONNECTION
532 /* Exit the inner array. */
533 free(field_addr.sub_location->sub_location);
534 field_addr.sub_location->sub_location = NULL;
535#endif /* FREECIV_JSON_CONNECTION */
536 }
537
538#ifdef FREECIV_JSON_CONNECTION
539 /* Exit the outer array. */
540 free(field_addr.sub_location);
541 field_addr.sub_location = NULL;
542#endif /* FREECIV_JSON_CONNECTION */
543 }'''%self.get_dict(vars())
544 else:
545 return '''
546 {
547 int i;
548
549#ifdef FREECIV_JSON_CONNECTION
550 /* Create the array. */
551 DIO_PUT(farray, &dout, &field_addr, %(array_size_u)s);
552
553 /* Enter the array. */
554 field_addr.sub_location = plocation_elem_new(0);
555#endif /* FREECIV_JSON_CONNECTION */
556
557 for (i = 0; i < %(array_size_u)s; i++) {
558#ifdef FREECIV_JSON_CONNECTION
559 /* Next array element. */
560 field_addr.sub_location->number = i;
561#endif /* FREECIV_JSON_CONNECTION */
562 %(c)s
563 }
564
565#ifdef FREECIV_JSON_CONNECTION
566 /* Exit array. */
567 free(field_addr.sub_location);
568 field_addr.sub_location = NULL;
569#endif /* FREECIV_JSON_CONNECTION */
570 }'''%self.get_dict(vars())
571
572 # Returns a code fragment which will get the field if the
573 # "fields" bitvector says so.
574 def get_get_wrapper(self,packet,i,deltafragment):
575 get=self.get_get(deltafragment)
576 if fold_bool_into_header and self.struct_type=="bool" and \
577 not self.is_array:
578 return " real_packet->%(name)s = BV_ISSET(fields, %(i)d);\n"%self.get_dict(vars())
579 get=prefix(" ",get)
580 log_macro=packet.log_macro
581 if packet.gen_log:
582 f=" %(log_macro)s(\" got field '%(name)s'\");\n"%self.get_dict(vars())
583 else:
584 f=""
585 return ''' if (BV_ISSET(fields, %(i)d)) {
586%(f)s%(get)s
587 }
588'''%self.get_dict(vars())
589
590 # Returns code which get this field.
591 def get_get(self,deltafragment):
592 return '''#ifdef FREECIV_JSON_CONNECTION
593field_addr.name = \"%(name)s\";
594#endif /* FREECIV_JSON_CONNECTION */
595'''%self.__dict__ \
596 + self.get_get_real(deltafragment);
597
598 # The code which get this field before it is wrapped in address adding.
599 def get_get_real(self,deltafragment):
600 if self.struct_type=="float" and not self.is_array:
601 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s, %(float_factor)d)) {
602 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
603}'''%self.__dict__
604 if self.dataio_type=="bitvector":
605 return '''if (!DIO_BV_GET(&din, &field_addr, real_packet->%(name)s)) {
606 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
607}'''%self.__dict__
608 if self.dataio_type in ["string","estring","city_map"] and \
609 self.is_array!=2:
610 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, real_packet->%(name)s, sizeof(real_packet->%(name)s))) {
611 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
612}'''%self.__dict__
613 if self.is_struct and self.is_array==0:
614 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s)) {
615 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
616}'''%self.__dict__
617 if not self.is_array:
618 if self.struct_type in ["int","bool"]:
619 return '''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s)) {
620 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
621}'''%self.__dict__
622 else:
623 return '''{
624 int readin;
625
626 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &readin)) {
627 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
628 }
629 real_packet->%(name)s = readin;
630}'''%self.__dict__
631
632 if self.is_struct:
633 if self.is_array==2:
634 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i][j])) {
635 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
636 }'''%self.__dict__
637 else:
638 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i])) {
639 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
640 }'''%self.__dict__
641 elif self.dataio_type=="string" or self.dataio_type=="estring":
642 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, real_packet->%(name)s[i], sizeof(real_packet->%(name)s[i]))) {
643 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
644 }'''%self.__dict__
645 elif self.struct_type=="float":
646 if self.is_array==2:
647 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i][j], %(float_factor)d)) {
648 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
649 }'''%self.__dict__
650 else:
651 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i], %(float_factor)d)) {
652 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
653 }'''%self.__dict__
654 elif self.is_array==2:
655 if self.struct_type in ["int","bool"]:
656 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i][j])) {
657 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
658 }'''%self.__dict__
659 else:
660 c='''{
661 int readin;
662
663 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &readin)) {
664 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
665 }
666 real_packet->%(name)s[i][j] = readin;
667 }'''%self.__dict__
668 elif self.struct_type in ["int","bool"]:
669 c='''if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &real_packet->%(name)s[i])) {
670 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
671 }'''%self.__dict__
672 else:
673 c='''{
674 int readin;
675
676 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, &readin)) {
677 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
678 }
679 real_packet->%(name)s[i] = readin;
680 }'''%self.__dict__
681
682 if self.is_array==2:
683 array_size_u=self.array_size1_u
684 array_size_d=self.array_size1_d
685 else:
686 array_size_u=self.array_size_u
687 array_size_d=self.array_size_d
688
689 if not self.diff or self.dataio_type=="memory":
690 if array_size_u != array_size_d:
691 extra='''
692 if (%(array_size_u)s > %(array_size_d)s) {
693 RECEIVE_PACKET_FIELD_ERROR(%(name)s, ": truncation array");
694 }'''%self.get_dict(vars())
695 else:
696 extra=""
697 if self.dataio_type=="memory":
698 return '''%(extra)s
699 if (!DIO_GET(%(dataio_type)s, &din, &field_addr, real_packet->%(name)s, %(array_size_u)s)) {
700 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
701 }'''%self.get_dict(vars())
702 elif self.is_array==2 and self.dataio_type!="string" \
703 and self.dataio_type!="estring":
704 return '''
705{
706 int i, j;
707
708#ifdef FREECIV_JSON_CONNECTION
709 /* Enter outer array. */
710 field_addr.sub_location = plocation_elem_new(0);
711#endif /* FREECIV_JSON_CONNECTION */
712%(extra)s
713 for (i = 0; i < %(array_size1_u)s; i++) {
714#ifdef FREECIV_JSON_CONNECTION
715 /* Update address of outer array element (inner array). */
716 field_addr.sub_location->number = i;
717
718 /* Enter inner array. */
719 field_addr.sub_location->sub_location = plocation_elem_new(0);
720#endif /* FREECIV_JSON_CONNECTION */
721 for (j = 0; j < %(array_size2_u)s; j++) {
722#ifdef FREECIV_JSON_CONNECTION
723 /* Update address of element in inner array. */
724 field_addr.sub_location->sub_location->number = j;
725#endif /* FREECIV_JSON_CONNECTION */
726 %(c)s
727 }
728
729#ifdef FREECIV_JSON_CONNECTION
730 /* Exit inner array. */
731 free(field_addr.sub_location->sub_location);
732 field_addr.sub_location->sub_location = NULL;
733#endif /* FREECIV_JSON_CONNECTION */
734 }
735
736#ifdef FREECIV_JSON_CONNECTION
737 /* Exit outer array. */
738 free(field_addr.sub_location);
739 field_addr.sub_location = NULL;
740#endif /* FREECIV_JSON_CONNECTION */
741}'''%self.get_dict(vars())
742 else:
743 return '''
744{
745 int i;
746
747#ifdef FREECIV_JSON_CONNECTION
748 /* Enter array. */
749 field_addr.sub_location = plocation_elem_new(0);
750#endif /* FREECIV_JSON_CONNECTION */
751%(extra)s
752 for (i = 0; i < %(array_size_u)s; i++) {
753#ifdef FREECIV_JSON_CONNECTION
754 field_addr.sub_location->number = i;
755#endif /* FREECIV_JSON_CONNECTION */
756 %(c)s
757 }
758
759#ifdef FREECIV_JSON_CONNECTION
760 /* Exit array. */
761 free(field_addr.sub_location);
762 field_addr.sub_location = NULL;
763#endif /* FREECIV_JSON_CONNECTION */
764}'''%self.get_dict(vars())
765 elif deltafragment and self.diff and self.is_array == 1:
766 return '''
767{
768#ifdef FREECIV_JSON_CONNECTION
769int count;
770
771/* Enter array. */
772field_addr.sub_location = plocation_elem_new(0);
773
774for (count = 0;; count++) {
775 int i;
776
777 field_addr.sub_location->number = count;
778
779 /* Enter diff array element (start at the index address). */
780 field_addr.sub_location->sub_location = plocation_elem_new(0);
781#else /* FREECIV_JSON_CONNECTION */
782while (TRUE) {
783 int i;
784#endif /* FREECIV_JSON_CONNECTION */
785
786 if (!DIO_GET(uint8, &din, &field_addr, &i)) {
787 RECEIVE_PACKET_FIELD_ERROR(%(name)s);
788 }
789 if (i == 255) {
790#ifdef FREECIV_JSON_CONNECTION
791 /* Exit diff array element. */
792 free(field_addr.sub_location->sub_location);
793 field_addr.sub_location->sub_location = NULL;
794
795 /* Exit diff array. */
796 free(field_addr.sub_location);
797 field_addr.sub_location = NULL;
798#endif /* FREECIV_JSON_CONNECTION */
799
800 break;
801 }
802 if (i > %(array_size_u)s) {
803 RECEIVE_PACKET_FIELD_ERROR(%(name)s,
804 \": unexpected value %%%%d \"
805 \"(> %(array_size_u)s) in array diff\",
806 i);
807 } else {
808#ifdef FREECIV_JSON_CONNECTION
809 /* Content address. */
810 field_addr.sub_location->sub_location->number = 1;
811#endif /* FREECIV_JSON_CONNECTION */
812 %(c)s
813 }
814
815#ifdef FREECIV_JSON_CONNECTION
816 /* Exit diff array element. */
817 free(field_addr.sub_location->sub_location);
818 field_addr.sub_location->sub_location = NULL;
819#endif /* FREECIV_JSON_CONNECTION */
820}
821
822#ifdef FREECIV_JSON_CONNECTION
823/* Exit array. */
824free(field_addr.sub_location);
825field_addr.sub_location = NULL;
826#endif /* FREECIV_JSON_CONNECTION */
827}'''%self.get_dict(vars())
828 else:
829 return '''
830{
831 int i;
832
833 for (i = 0; i < %(array_size_u)s; i++) {
834 %(c)s
835 }
836}'''%self.get_dict(vars())
837
838
839# Class which represents a capability variant.
841 def __init__(self,poscaps,negcaps,name,fields,packet,no):
842 self.log_macro=use_log_macro
843 self.gen_stats=generate_stats
844 self.gen_log=generate_logs
845 self.name=name
846 self.packet_name=packet.name
847 self.fields=fields
848 self.no=no
849
850 self.no_packet=packet.no_packet
851 self.want_post_recv=packet.want_post_recv
852 self.want_pre_send=packet.want_pre_send
853 self.want_post_send=packet.want_post_send
854 self.type=packet.type
855 self.delta=packet.delta
856 self.is_info=packet.is_info
857 self.differ_used = (
858 (not self.no_packet)
859 and self.delta
860 and (
861 self.is_info != "no"
862 or any(
863 not field.folded_into_head
864 for field in self.fields
865 )
866 )
867 )
868 self.cancel=packet.cancel
869 self.want_force=packet.want_force
870
871 self.poscaps=poscaps
872 self.negcaps=negcaps
873 if self.poscaps or self.negcaps:
874 def f(cap):
875 return 'has_capability("%s", capability)'%(cap)
876 t=(list(map(lambda x,f=f: f(x),self.poscaps))+
877 list(map(lambda x,f=f: '!'+f(x),self.negcaps)))
878 self.condition=" && ".join(t)
879 else:
880 self.condition="TRUE"
881 self.key_fields=list(filter(lambda x:x.is_key,self.fields))
882 self.other_fields=list(filter(lambda x:not x.is_key,self.fields))
884 self.keys_format=", ".join(["%d"]*len(self.key_fields))
885 self.keys_arg=", ".join(map(lambda x:"real_packet->"+x.name,
886 self.key_fields))
887 if self.keys_arg:
888 self.keys_arg=",\n "+self.keys_arg
889
890 if len(self.fields)==0:
891 self.delta=0
892 self.no_packet=1
893
894 if len(self.fields)>5 or self.name.split("_")[1]=="ruleset":
896
899 self.extra_send_args3=", ".join(
900 map(lambda x:"%s%s"%(x.get_handle_type(), x.name),
901 self.fields))
902 if self.extra_send_args3:
904
905 if not self.no_packet:
906 self.extra_send_args=', const struct %(packet_name)s *packet'%self.__dict__+self.extra_send_args
907 self.extra_send_args2=', packet'+self.extra_send_args2
908
909 if self.want_force:
910 self.extra_send_args=self.extra_send_args+', bool force_to_send'
911 self.extra_send_args2=self.extra_send_args2+', force_to_send'
912 self.extra_send_args3=self.extra_send_args3+', bool force_to_send'
913
914 self.receive_prototype='static struct %(packet_name)s *receive_%(name)s(struct connection *pc)'%self.__dict__
915 self.send_prototype='static int send_%(name)s(struct connection *pc%(extra_send_args)s)'%self.__dict__
916
917
918 if self.no_packet:
919 self.send_handler='phandlers->send[%(type)s].no_packet = (int(*)(struct connection *)) send_%(name)s;'%self.__dict__
920 elif self.want_force:
921 self.send_handler='phandlers->send[%(type)s].force_to_send = (int(*)(struct connection *, const void *, bool)) send_%(name)s;'%self.__dict__
922 else:
923 self.send_handler='phandlers->send[%(type)s].packet = (int(*)(struct connection *, const void *)) send_%(name)s;'%self.__dict__
924 self.receive_handler='phandlers->receive[%(type)s] = (void *(*)(struct connection *)) receive_%(name)s;'%self.__dict__
925
926 # See Field.get_dict
927 def get_dict(self,vars):
928 result=self.__dict__.copy()
929 result.update(vars)
930 return result
931
932 # Returns a code fragment which contains the declarations of the
933 # statistical counters of this packet.
934 def get_stats(self):
935 names=map(lambda x:'"'+x.name+'"',self.other_fields)
936 names=", ".join(names)
937
938 return '''static int stats_%(name)s_sent;
939static int stats_%(name)s_discarded;
940static int stats_%(name)s_counters[%(bits)d];
941static char *stats_%(name)s_names[] = {%(names)s};
942
943'''%self.get_dict(vars())
944
945 # Returns a code fragment which declares the packet specific
946 # bitvector. Each bit in this bitvector represents one non-key
947 # field.
948 def get_bitvector(self):
949 return "BV_DEFINE(%(name)s_fields, %(bits)d);\n"%self.__dict__
950
951 # Returns a code fragment which is the packet specific part of
952 # the delta_stats_report() function.
954 return '''
955 if (stats_%(name)s_sent > 0
956 && stats_%(name)s_discarded != stats_%(name)s_sent) {
957 log_test(\"%(name)s %%d out of %%d got discarded\",
958 stats_%(name)s_discarded, stats_%(name)s_sent);
959 for (i = 0; i < %(bits)d; i++) {
960 if (stats_%(name)s_counters[i] > 0) {
961 log_test(\" %%4d / %%4d: %%2d = %%s\",
962 stats_%(name)s_counters[i],
963 (stats_%(name)s_sent - stats_%(name)s_discarded),
964 i, stats_%(name)s_names[i]);
965 }
966 }
967 }
968'''%self.__dict__
969
970 # Returns a code fragment which is the packet specific part of
971 # the delta_stats_reset() function.
972 def get_reset_part(self):
973 return '''
974 stats_%(name)s_sent = 0;
975 stats_%(name)s_discarded = 0;
976 memset(stats_%(name)s_counters, 0,
977 sizeof(stats_%(name)s_counters));
978'''%self.__dict__
979
980 # Returns a code fragment which is the implementation of the hash
981 # function. The hash function is using all key fields.
982 def get_hash(self):
983 if len(self.key_fields)==0:
984 return "#define hash_%(name)s hash_const\n\n"%self.__dict__
985 else:
986 intro='''static genhash_val_t hash_%(name)s(const void *vkey)
987{
988'''%self.__dict__
989
990 body=''' const struct %(packet_name)s *key = (const struct %(packet_name)s *) vkey;
991
992'''%self.__dict__
993
994 keys=list(map(lambda x:"key->"+x.name,self.key_fields))
995 if len(keys)==1:
996 a=keys[0]
997 elif len(keys)==2:
998 a="(%s << 8) ^ %s"%(keys[0], keys[1])
999 else:
1000 assert 0
1001 body=body+(' return %s;\n'%a)
1002 extro="}\n\n"
1003 return intro+body+extro
1004
1005 # Returns a code fragment which is the implementation of the cmp
1006 # function. The cmp function is using all key fields. The cmp
1007 # function is used for the hash table.
1008 def get_cmp(self):
1009 if len(self.key_fields)==0:
1010 return "#define cmp_%(name)s cmp_const\n\n"%self.__dict__
1011 else:
1012 intro='''static bool cmp_%(name)s(const void *vkey1, const void *vkey2)
1013{
1014'''%self.__dict__
1015 body=""
1016 body=body+''' const struct %(packet_name)s *key1 = (const struct %(packet_name)s *) vkey1;
1017 const struct %(packet_name)s *key2 = (const struct %(packet_name)s *) vkey2;
1018
1019'''%self.__dict__
1020 for field in self.key_fields:
1021 body=body+''' return key1->%s == key2->%s;
1022'''%(field.name,field.name)
1023 extro="}\n"
1024 return intro+body+extro
1025
1026 # Returns a code fragment which is the implementation of the send
1027 # function. This is one of the two real functions. So it is rather
1028 # complex to create.
1029 def get_send(self):
1030 temp='''%(send_prototype)s
1031{
1032<real_packet1><delta_header> SEND_PACKET_START(%(type)s);
1033<faddr><log><report><pre1><body><pre2><post> SEND_PACKET_END(%(type)s);
1034}
1035
1036'''
1037 if self.gen_stats:
1038 report='''
1039 stats_total_sent++;
1040 stats_%(name)s_sent++;
1041'''
1042 else:
1043 report=""
1044 if self.gen_log:
1045 log='\n %(log_macro)s("%(name)s: sending info about (%(keys_format)s)"%(keys_arg)s);\n'
1046 else:
1047 log=""
1048 if self.want_pre_send:
1049 pre1='''
1050 {
1051 struct %(packet_name)s *tmp = fc_malloc(sizeof(*tmp));
1052
1053 *tmp = *packet;
1054 pre_send_%(packet_name)s(pc, tmp);
1055 real_packet = tmp;
1056 }
1057'''
1058 pre2='''
1059 if (real_packet != packet) {
1060 free((void *) real_packet);
1061 }
1062'''
1063 else:
1064 pre1=""
1065 pre2=""
1066
1067 if not self.no_packet:
1068 real_packet1=" const struct %(packet_name)s *real_packet = packet;\n"
1069 else:
1070 real_packet1=""
1071
1072 if not self.no_packet:
1073 if self.delta:
1074 if self.want_force:
1075 diff='force_to_send'
1076 else:
1077 diff='0'
1078 delta_header = '''#ifdef FREECIV_DELTA_PROTOCOL
1079 %(name)s_fields fields;
1080 struct %(packet_name)s *old;
1081'''
1082 delta_header2 = ''' struct genhash **hash = pc->phs.sent + %(type)s;
1083'''
1084 if self.is_info != "no":
1085 delta_header2 = delta_header2 + ''' int different = %(diff)s;
1086'''
1087 delta_header2 = delta_header2 + '''#endif /* FREECIV_DELTA_PROTOCOL */
1088'''
1089 body=self.get_delta_send_body()+"\n#ifndef FREECIV_DELTA_PROTOCOL"
1090 else:
1091 delta_header=""
1092 body="#if 1 /* To match endif */"
1093 body=body+"\n"
1094 for field in self.fields:
1095 body=body+field.get_put(0)+"\n"
1096 body=body+"\n#endif\n"
1097 else:
1098 body=""
1099 delta_header=""
1100
1101 if self.want_post_send:
1102 if self.no_packet:
1103 post=" post_send_%(packet_name)s(pc, NULL);\n"
1104 else:
1105 post=" post_send_%(packet_name)s(pc, real_packet);\n"
1106 else:
1107 post=""
1108
1109 if len(self.fields) != 0:
1110 faddr = '''#ifdef FREECIV_JSON_CONNECTION
1111 struct plocation field_addr;
1112 {
1113 struct plocation *field_addr_tmp = plocation_field_new(NULL);
1114 field_addr = *field_addr_tmp;
1115 FC_FREE(field_addr_tmp);
1116 }
1117#endif /* FREECIV_JSON_CONNECTION */
1118'''
1119 else:
1120 faddr = ""
1121
1122 if delta_header != "":
1123 if self.differ_used:
1124 delta_header = delta_header + ''' bool differ;
1125''' + delta_header2
1126 else:
1127 delta_header = delta_header + delta_header2
1128 for i in range(2):
1129 for k,v in vars().items():
1130 if type(v)==type(""):
1131 temp=temp.replace("<%s>"%k,v)
1132 return temp%self.get_dict(vars())
1133
1134 # '''
1135
1136 # Helper for get_send()
1138 intro='''
1139#ifdef FREECIV_DELTA_PROTOCOL
1140 if (NULL == *hash) {
1141 *hash = genhash_new_full(hash_%(name)s, cmp_%(name)s,
1142 NULL, NULL, NULL, free);
1143 }
1144 BV_CLR_ALL(fields);
1145
1146 if (!genhash_lookup(*hash, real_packet, (void **) &old)) {
1147 old = fc_malloc(sizeof(*old));
1148 *old = *real_packet;
1149 genhash_insert(*hash, old, old);
1150 memset(old, 0, sizeof(*old));
1151'''
1152 if self.is_info != "no":
1153 intro = intro + ''' different = 1; /* Force to send. */
1154'''
1155 intro = intro + ''' }
1156'''
1157 body=""
1158 for i in range(len(self.other_fields)):
1159 field=self.other_fields[i]
1160 body=body+field.get_cmp_wrapper(i, self)
1161 if self.gen_log:
1162 fl=' %(log_macro)s(" no change -> discard");\n'
1163 else:
1164 fl=""
1165 if self.gen_stats:
1166 s=' stats_%(name)s_discarded++;\n'
1167 else:
1168 s=""
1169
1170 if self.is_info != "no":
1171 body=body+'''
1172 if (different == 0) {
1173%(fl)s%(s)s<pre2> return 0;
1174 }
1175'''%self.get_dict(vars())
1176
1177 body=body+'''
1178#ifdef FREECIV_JSON_CONNECTION
1179 field_addr.name = "fields";
1180#endif /* FREECIV_JSON_CONNECTION */
1181 DIO_BV_PUT(&dout, &field_addr, fields);
1182'''
1183
1184 for field in self.key_fields:
1185 body=body+field.get_put(1)+"\n"
1186 body=body+"\n"
1187
1188 for i in range(len(self.other_fields)):
1189 field=self.other_fields[i]
1190 body=body+field.get_put_wrapper(self,i,1)
1191 body=body+'''
1192 *old = *real_packet;
1193'''
1194
1195 # Cancel some is-info packets.
1196 for i in self.cancel:
1197 body=body+'''
1198 hash = pc->phs.sent + %s;
1199 if (NULL != *hash) {
1200 genhash_remove(*hash, real_packet);
1201 }
1202'''%i
1203 body=body+'''#endif /* FREECIV_DELTA_PROTOCOL */'''
1204
1205 return intro+body
1206
1207 # Returns a code fragment which is the implementation of the receive
1208 # function. This is one of the two real functions. So it is rather
1209 # complex to create.
1210 def get_receive(self):
1211 temp='''%(receive_prototype)s
1212{
1213<delta_header> RECEIVE_PACKET_START(%(packet_name)s, real_packet);
1214<faddr><delta_body1><body1><log><body2><post> RECEIVE_PACKET_END(real_packet);
1215}
1216
1217'''
1218 if self.delta:
1219 delta_header='''#ifdef FREECIV_DELTA_PROTOCOL
1220 %(name)s_fields fields;
1221 struct %(packet_name)s *old;
1222 struct genhash **hash = pc->phs.received + %(type)s;
1223#endif /* FREECIV_DELTA_PROTOCOL */
1224'''
1225 delta_body1='''
1226#ifdef FREECIV_DELTA_PROTOCOL
1227#ifdef FREECIV_JSON_CONNECTION
1228 field_addr.name = "fields";
1229#endif /* FREECIV_JSON_CONNECTION */
1230 DIO_BV_GET(&din, &field_addr, fields);
1231 '''
1232 body1=""
1233 for field in self.key_fields:
1234 body1=body1+prefix(" ",field.get_get(1))+"\n"
1235 body1=body1+"\n#else /* FREECIV_DELTA_PROTOCOL */\n"
1236 body2=self.get_delta_receive_body()
1237 else:
1238 delta_header=""
1239 delta_body1=""
1240 body1="#if 1 /* To match endif */\n"
1241 body2=""
1242 nondelta=""
1243 for field in self.fields:
1244 nondelta=nondelta+prefix(" ",field.get_get(0))+"\n"
1245 if not nondelta:
1246 nondelta=" real_packet->__dummy = 0xff;"
1247 body1=body1+nondelta+"\n#endif\n"
1248
1249 if self.gen_log:
1250 log=' %(log_macro)s("%(name)s: got info about (%(keys_format)s)"%(keys_arg)s);\n'
1251 else:
1252 log=""
1253
1254 if self.want_post_recv:
1255 post=" post_receive_%(packet_name)s(pc, real_packet);\n"
1256 else:
1257 post=""
1258
1259 if len(self.fields) != 0:
1260 faddr = '''#ifdef FREECIV_JSON_CONNECTION
1261 struct plocation field_addr;
1262 {
1263 struct plocation *field_addr_tmp = plocation_field_new(NULL);
1264 field_addr = *field_addr_tmp;
1265 FC_FREE(field_addr_tmp);
1266 }
1267#endif /* FREECIV_JSON_CONNECTION */
1268'''
1269 else:
1270 faddr = ""
1271
1272 for i in range(2):
1273 for k,v in vars().items():
1274 if type(v)==type(""):
1275 temp=temp.replace("<%s>"%k,v)
1276 return temp%self.get_dict(vars())
1277
1278 # Helper for get_receive()
1280 key1=map(lambda x:" %s %s = real_packet->%s;"%(x.struct_type,x.name,x.name),self.key_fields)
1281 key2=map(lambda x:" real_packet->%s = %s;"%(x.name,x.name),self.key_fields)
1282 key1="\n".join(key1)
1283 key2="\n".join(key2)
1284 if key1: key1=key1+"\n\n"
1285 if key2: key2="\n\n"+key2
1286 if self.gen_log:
1287 fl=' %(log_macro)s(" no old info");\n'
1288 else:
1289 fl=""
1290 body='''
1291#ifdef FREECIV_DELTA_PROTOCOL
1292 if (NULL == *hash) {
1293 *hash = genhash_new_full(hash_%(name)s, cmp_%(name)s,
1294 NULL, NULL, NULL, free);
1295 }
1296
1297 if (genhash_lookup(*hash, real_packet, (void **) &old)) {
1298 *real_packet = *old;
1299 } else {
1300%(key1)s%(fl)s memset(real_packet, 0, sizeof(*real_packet));%(key2)s
1301 }
1302
1303'''%self.get_dict(vars())
1304 for i in range(len(self.other_fields)):
1305 field=self.other_fields[i]
1306 body=body+field.get_get_wrapper(self,i,1)
1307
1308 extro='''
1309 if (NULL == old) {
1310 old = fc_malloc(sizeof(*old));
1311 *old = *real_packet;
1312 genhash_insert(*hash, old, old);
1313 } else {
1314 *old = *real_packet;
1315 }
1316'''%self.get_dict(vars())
1317
1318 # Cancel some is-info packets.
1319 for i in self.cancel:
1320 extro=extro+'''
1321 hash = pc->phs.received + %s;
1322 if (NULL != *hash) {
1323 genhash_remove(*hash, real_packet);
1324 }
1325'''%i
1326
1327 return body+extro+'''
1328#endif /* FREECIV_DELTA_PROTOCOL */
1329'''
1330
1331# Class which represents a packet. A packet contains a list of fields.
1333 def __init__(self,str, types):
1334 self.types=types
1335 self.log_macro=use_log_macro
1336 self.gen_stats=generate_stats
1337 self.gen_log=generate_logs
1338 str=str.strip()
1339 lines=str.split("\n")
1340
1341 mo = re.search(r"^\s*(\S+)\s*=\s*(\d+)\s*;\s*(.*?)\s*$", lines[0])
1342 assert mo,repr(lines[0])
1343
1344 self.type=mo.group(1)
1345 self.name=self.type.lower()
1346 self.type_number=int(mo.group(2))
1347 assert 0<=self.type_number<=65535
1348 dummy=mo.group(3)
1349
1350 del lines[0]
1351
1352 arr=list(item.strip() for item in dummy.split(",") if item)
1353
1354 self.dirs=[]
1355
1356 if "sc" in arr:
1357 self.dirs.append("sc")
1358 arr.remove("sc")
1359 if "cs" in arr:
1360 self.dirs.append("cs")
1361 arr.remove("cs")
1362 assert len(self.dirs)>0,repr(self.name)+repr(self.dirs)
1363
1364 # "no" means normal packet
1365 # "yes" means is-info packet
1366 # "game" means is-game-info packet
1367 self.is_info="no"
1368 if "is-info" in arr:
1369 self.is_info="yes"
1370 arr.remove("is-info")
1371 if "is-game-info" in arr:
1372 self.is_info="game"
1373 arr.remove("is-game-info")
1374
1375 self.want_pre_send="pre-send" in arr
1376 if self.want_pre_send: arr.remove("pre-send")
1377
1378 self.want_post_recv="post-recv" in arr
1379 if self.want_post_recv: arr.remove("post-recv")
1380
1381 self.want_post_send="post-send" in arr
1382 if self.want_post_send: arr.remove("post-send")
1383
1384 self.delta="no-delta" not in arr
1385 if not self.delta: arr.remove("no-delta")
1386
1387 self.no_packet="no-packet" in arr
1388 if self.no_packet: arr.remove("no-packet")
1389
1390 self.handle_via_packet="handle-via-packet" in arr
1391 if self.handle_via_packet: arr.remove("handle-via-packet")
1392
1393 self.handle_per_conn="handle-per-conn" in arr
1394 if self.handle_per_conn: arr.remove("handle-per-conn")
1395
1396 self.no_handle="no-handle" in arr
1397 if self.no_handle: arr.remove("no-handle")
1398
1399 self.dsend_given="dsend" in arr
1400 if self.dsend_given: arr.remove("dsend")
1401
1402 self.want_lsend="lsend" in arr
1403 if self.want_lsend: arr.remove("lsend")
1404
1405 self.want_force="force" in arr
1406 if self.want_force: arr.remove("force")
1407
1408 self.cancel=[]
1409 removes=[]
1410 remaining=[]
1411 for i in arr:
1412 mo = re.search(r"^cancel\‍((.*)\‍)$", i)
1413 if mo:
1414 self.cancel.append(mo.group(1))
1415 continue
1416 remaining.append(i)
1417 arr=remaining
1418
1419 assert len(arr)==0,repr(arr)
1420
1421 self.fields=[]
1422 for i in lines:
1423 self.fields=self.fields+parse_fields(i,types)
1424 self.key_fields=list(filter(lambda x:x.is_key,self.fields))
1425 self.other_fields=list(filter(lambda x:not x.is_key,self.fields))
1427 self.keys_format=", ".join(["%d"]*len(self.key_fields))
1428 self.keys_arg=", ".join(map(lambda x:"real_packet->"+x.name,
1429 self.key_fields))
1430 if self.keys_arg:
1431 self.keys_arg=",\n "+self.keys_arg
1432
1433
1435
1436 if len(self.fields)==0:
1437 self.delta=0
1438 self.no_packet=1
1439 assert not self.want_dsend,"dsend for a packet without fields isn't useful"
1440
1441 if len(self.fields)>5 or self.name.split("_")[1]=="ruleset":
1442 self.handle_via_packet=1
1443
1446 self.extra_send_args3=", ".join(
1447 map(lambda x:"%s%s"%(x.get_handle_type(), x.name),
1448 self.fields))
1449 if self.extra_send_args3:
1450 self.extra_send_args3=", "+self.extra_send_args3
1451
1452 if not self.no_packet:
1453 self.extra_send_args=', const struct %(name)s *packet'%self.__dict__+self.extra_send_args
1454 self.extra_send_args2=', packet'+self.extra_send_args2
1455
1456 if self.want_force:
1457 self.extra_send_args=self.extra_send_args+', bool force_to_send'
1458 self.extra_send_args2=self.extra_send_args2+', force_to_send'
1459 self.extra_send_args3=self.extra_send_args3+', bool force_to_send'
1460
1461 self.send_prototype='int send_%(name)s(struct connection *pc%(extra_send_args)s)'%self.__dict__
1462 if self.want_lsend:
1463 self.lsend_prototype='void lsend_%(name)s(struct conn_list *dest%(extra_send_args)s)'%self.__dict__
1464 if self.want_dsend:
1465 self.dsend_prototype='int dsend_%(name)s(struct connection *pc%(extra_send_args3)s)'%self.__dict__
1466 if self.want_lsend:
1467 self.dlsend_prototype='void dlsend_%(name)s(struct conn_list *dest%(extra_send_args3)s)'%self.__dict__
1468
1469 # create cap variants
1470 all_caps={}
1471 for f in self.fields:
1472 if f.add_cap: all_caps[f.add_cap]=1
1473 if f.remove_cap: all_caps[f.remove_cap]=1
1474
1475 all_caps=all_caps.keys()
1476 choices=get_choices(all_caps)
1477 self.variants=[]
1478 for i in range(len(choices)):
1479 poscaps=choices[i]
1480 negcaps=without(all_caps,poscaps)
1481 fields=[]
1482 for field in self.fields:
1483 if not field.add_cap and not field.remove_cap:
1484 fields.append(field)
1485 elif field.add_cap and field.add_cap in poscaps:
1486 fields.append(field)
1487 elif field.remove_cap and field.remove_cap in negcaps:
1488 fields.append(field)
1489 no=i+100
1490
1491 self.variants.append(Variant(poscaps,negcaps,"%s_%d"%(self.name,no),fields,self,no))
1492
1493
1494 # Returns a code fragment which contains the struct for this packet.
1495 def get_struct(self):
1496 intro="struct %(name)s {\n"%self.__dict__
1497 extro="};\n\n"
1498
1499 body=""
1500 for field in self.key_fields+self.other_fields:
1501 body=body+" %s;\n"%field.get_declar()
1502 if not body:
1503 body=" char __dummy; /* to avoid malloc(0); */\n"
1504 return intro+body+extro
1505 # '''
1506
1507 # Returns a code fragment which represents the prototypes of the
1508 # send and receive functions for the header file.
1510 result=self.send_prototype+";\n"
1511 if self.want_lsend:
1512 result=result+self.lsend_prototype+";\n"
1513 if self.want_dsend:
1514 result=result+self.dsend_prototype+";\n"
1515 if self.want_lsend:
1516 result=result+self.dlsend_prototype+";\n"
1517 return result+"\n"
1518
1519 # See Field.get_dict
1520 def get_dict(self,vars):
1521 result=self.__dict__.copy()
1522 result.update(vars)
1523 return result
1524
1525 def get_send(self):
1526 if self.no_packet:
1527 func="no_packet"
1528 args=""
1529 elif self.want_force:
1530 func="force_to_send"
1531 args=", packet, force_to_send"
1532 else:
1533 func="packet"
1534 args=", packet"
1535
1536 return '''%(send_prototype)s
1537{
1538 if (!pc->used) {
1539 log_error("WARNING: trying to send data to the closed connection %%s",
1540 conn_description(pc));
1541 return -1;
1542 }
1543 fc_assert_ret_val_msg(pc->phs.handlers->send[%(type)s].%(func)s != NULL, -1,
1544 "Handler for %(type)s not installed");
1545 return pc->phs.handlers->send[%(type)s].%(func)s(pc%(args)s);
1546}
1547
1548'''%self.get_dict(vars())
1549
1550 def get_variants(self):
1551 result=""
1552 for v in self.variants:
1553 if v.delta:
1554 result=result+"#ifdef FREECIV_DELTA_PROTOCOL\n"
1555 result=result+v.get_hash()
1556 result=result+v.get_cmp()
1557 result=result+v.get_bitvector()
1558 result=result+"#endif /* FREECIV_DELTA_PROTOCOL */\n\n"
1559 result=result+v.get_receive()
1560 result=result+v.get_send()
1561 return result
1562
1563 # Returns a code fragment which is the implementation of the
1564 # lsend function.
1565 def get_lsend(self):
1566 if not self.want_lsend: return ""
1567 return '''%(lsend_prototype)s
1568{
1569 conn_list_iterate(dest, pconn) {
1570 send_%(name)s(pconn%(extra_send_args2)s);
1571 } conn_list_iterate_end;
1572}
1573
1574'''%self.__dict__
1575
1576 # Returns a code fragment which is the implementation of the
1577 # dsend function.
1578 def get_dsend(self):
1579 if not self.want_dsend: return ""
1580 fill="\n".join(map(lambda x:x.get_fill(),self.fields))
1581 return '''%(dsend_prototype)s
1582{
1583 struct %(name)s packet, *real_packet = &packet;
1584
1585%(fill)s
1586
1587 return send_%(name)s(pc, real_packet);
1588}
1589
1590'''%self.get_dict(vars())
1591
1592 # Returns a code fragment which is the implementation of the
1593 # dlsend function.
1594 def get_dlsend(self):
1595 if not (self.want_lsend and self.want_dsend): return ""
1596 fill="\n".join(map(lambda x:x.get_fill(),self.fields))
1597 return '''%(dlsend_prototype)s
1598{
1599 struct %(name)s packet, *real_packet = &packet;
1600
1601%(fill)s
1602
1603 lsend_%(name)s(dest, real_packet);
1604}
1605
1606'''%self.get_dict(vars())
1607
1608# Returns a code fragment which is the implementation of the
1609# packet_functional_capability string.
1611 all_caps={}
1612 for p in packets:
1613 for f in p.fields:
1614 if f.add_cap: all_caps[f.add_cap]=1
1615 if f.remove_cap: all_caps[f.remove_cap]=1
1616 return '''
1617const char *const packet_functional_capability = "%s";
1618'''%' '.join(all_caps.keys())
1619
1620# Returns a code fragment which is the implementation of the
1621# delta_stats_report() function.
1622def get_report(packets):
1623 if not generate_stats: return 'void delta_stats_report(void) {}\n\n'
1624
1625 intro='''
1626void delta_stats_report(void) {
1627 int i;
1628
1629'''
1630 extro='}\n\n'
1631 body=""
1632
1633 for p in packets:
1634 body=body+p.get_report_part()
1635 return intro+body+extro
1636
1637# Returns a code fragment which is the implementation of the
1638# delta_stats_reset() function.
1639def get_reset(packets):
1640 if not generate_stats: return 'void delta_stats_reset(void) {}\n\n'
1641 intro='''
1642void delta_stats_reset(void) {
1643'''
1644 extro='}\n\n'
1645 body=""
1646
1647 for p in packets:
1648 body=body+p.get_reset_part()
1649 return intro+body+extro
1650
1651# Returns a code fragment which is the implementation of the
1652# packet_name() function.
1653def get_packet_name(packets):
1654 intro='''const char *packet_name(enum packet_type type)
1655{
1656 static const char *const names[PACKET_LAST] = {
1657'''
1658
1659 mapping={}
1660 for p in packets:
1661 mapping[p.type_number]=p
1662 sorted=list(mapping.keys())
1663 sorted.sort()
1664
1665 last=-1
1666 body=""
1667 for n in sorted:
1668 for i in range(last + 1, n):
1669 body=body+' "unknown",\n'
1670 body=body+' "%s",\n'%mapping[n].type
1671 last=n
1672
1673 extro=''' };
1674
1675 return (type < PACKET_LAST ? names[type] : "unknown");
1676}
1677
1678'''
1679 return intro+body+extro
1680
1681# Returns a code fragment which is the implementation of the
1682# packet_has_game_info_flag() function.
1684 intro='''bool packet_has_game_info_flag(enum packet_type type)
1685{
1686 static const bool flag[PACKET_LAST] = {
1687'''
1688
1689 mapping={}
1690 for p in packets:
1691 mapping[p.type_number]=p
1692 sorted=list(mapping.keys())
1693 sorted.sort()
1694
1695 last=-1
1696 body=""
1697 for n in sorted:
1698 for i in range(last + 1, n):
1699 body=body+' FALSE,\n'
1700 if mapping[n].is_info!="game":
1701 body=body+' FALSE, /* %s */\n'%mapping[n].type
1702 else:
1703 body=body+' TRUE, /* %s */\n'%mapping[n].type
1704 last=n
1705
1706 extro=''' };
1707
1708 return (type < PACKET_LAST ? flag[type] : FALSE);
1709}
1710
1711'''
1712 return intro+body+extro
1713
1714# Returns a code fragment which is the implementation of the
1715# packet_handlers_fill_initial() function.
1717 intro='''void packet_handlers_fill_initial(struct packet_handlers *phandlers)
1718{
1719'''
1720 all_caps={}
1721 for p in packets:
1722 for f in p.fields:
1723 if f.add_cap: all_caps[f.add_cap]=1
1724 if f.remove_cap: all_caps[f.remove_cap]=1
1725 for cap in all_caps.keys():
1726 intro=intro+''' fc_assert_msg(has_capability("%s", our_capability),
1727 "Packets have support for unknown '%s' capability!");
1728'''%(cap,cap)
1729
1730 sc_packets=[]
1731 cs_packets=[]
1732 unrestricted=[]
1733 for p in packets:
1734 if len(p.variants)==1:
1735 # Packets with variants are correctly handled in
1736 # packet_handlers_fill_capability(). They may remain without
1737 # handler at connecting time, because it would be anyway wrong
1738 # to use them before the network capability string would be
1739 # known.
1740 if len(p.dirs)==1 and p.dirs[0]=="sc":
1741 sc_packets.append(p)
1742 elif len(p.dirs)==1 and p.dirs[0]=="cs":
1743 cs_packets.append(p)
1744 else:
1745 unrestricted.append(p)
1746
1747 body=""
1748 for p in unrestricted:
1749 body=body+''' %(send_handler)s
1750 %(receive_handler)s
1751'''%p.variants[0].__dict__
1752 body=body+''' if (is_server()) {
1753'''
1754 for p in sc_packets:
1755 body=body+''' %(send_handler)s
1756'''%p.variants[0].__dict__
1757 for p in cs_packets:
1758 body=body+''' %(receive_handler)s
1759'''%p.variants[0].__dict__
1760 body=body+''' } else {
1761'''
1762 for p in cs_packets:
1763 body=body+''' %(send_handler)s
1764'''%p.variants[0].__dict__
1765 for p in sc_packets:
1766 body=body+''' %(receive_handler)s
1767'''%p.variants[0].__dict__
1768
1769 extro=''' }
1770}
1771
1772'''
1773 return intro+body+extro
1774
1775# Returns a code fragment which is the implementation of the
1776# packet_handlers_fill_capability() function.
1778 intro='''void packet_handlers_fill_capability(struct packet_handlers *phandlers,
1779 const char *capability)
1780{
1781'''
1782
1783 sc_packets=[]
1784 cs_packets=[]
1785 unrestricted=[]
1786 for p in packets:
1787 if len(p.variants)>1:
1788 if len(p.dirs)==1 and p.dirs[0]=="sc":
1789 sc_packets.append(p)
1790 elif len(p.dirs)==1 and p.dirs[0]=="cs":
1791 cs_packets.append(p)
1792 else:
1793 unrestricted.append(p)
1794
1795 body=""
1796 for p in unrestricted:
1797 body=body+" "
1798 for v in p.variants:
1799 body=body+'''if (%(condition)s) {
1800 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1801 %(send_handler)s
1802 %(receive_handler)s
1803 } else '''%v.__dict__
1804 body=body+'''{
1805 log_error("Unknown %(type)s variant for cap %%s", capability);
1806 }
1807'''%v.__dict__
1808 if len(cs_packets)>0 or len(sc_packets)>0:
1809 body=body+''' if (is_server()) {
1810'''
1811 for p in sc_packets:
1812 body=body+" "
1813 for v in p.variants:
1814 body=body+'''if (%(condition)s) {
1815 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1816 %(send_handler)s
1817 } else '''%v.__dict__
1818 body=body+'''{
1819 log_error("Unknown %(type)s variant for cap %%s", capability);
1820 }
1821'''%v.__dict__
1822 for p in cs_packets:
1823 body=body+" "
1824 for v in p.variants:
1825 body=body+'''if (%(condition)s) {
1826 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1827 %(receive_handler)s
1828 } else '''%v.__dict__
1829 body=body+'''{
1830 log_error("Unknown %(type)s variant for cap %%s", capability);
1831 }
1832'''%v.__dict__
1833 body=body+''' } else {
1834'''
1835 for p in cs_packets:
1836 body=body+" "
1837 for v in p.variants:
1838 body=body+'''if (%(condition)s) {
1839 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1840 %(send_handler)s
1841 } else '''%v.__dict__
1842 body=body+'''{
1843 log_error("Unknown %(type)s variant for cap %%s", capability);
1844 }
1845'''%v.__dict__
1846 for p in sc_packets:
1847 body=body+" "
1848 for v in p.variants:
1849 body=body+'''if (%(condition)s) {
1850 %(log_macro)s("%(type)s: using variant=%(no)s cap=%%s", capability);
1851 %(receive_handler)s
1852 } else '''%v.__dict__
1853 body=body+'''{
1854 log_error("Unknown %(type)s variant for cap %%s", capability);
1855 }
1856'''%v.__dict__
1857 body=body+''' }
1858'''
1859
1860 extro='''}
1861'''
1862 return intro+body+extro
1863
1864# Returns a code fragment which is the declartion of
1865# "enum packet_type".
1866def get_enum_packet(packets):
1867 intro="enum packet_type {\n"
1868
1869 mapping={}
1870 for p in packets:
1871 if p.type_number in mapping :
1872 print(p.name,mapping[p.type_number].name)
1873 assert 0
1874 mapping[p.type_number]=p
1875 sorted=list(mapping.keys())
1876 sorted.sort()
1877
1878 last=-1
1879 body=""
1880 for i in sorted:
1881 p=mapping[i]
1882 if i!=last+1:
1883 line=" %s = %d,"%(p.type,i)
1884 else:
1885 line=" %s,"%(p.type)
1886
1887 if (i%10)==0:
1888 line="%-40s /* %d */"%(line,i)
1889 body=body+line+"\n"
1890
1891 last=i
1892 extro='''
1893 PACKET_LAST /* leave this last */
1894};
1895
1896'''
1897 return intro+body+extro
1898
1900 # The obvious way:
1901 # s=re.sub(r"/\*(.|\n)*?\*/","",s)
1902 # doesn't work with python version 2.2 and 2.3.
1903 # Do it by hand then.
1904 result=""
1905 for i in filter(lambda x:x,s.split("/*")):
1906 l=i.split("*/",1)
1907 assert len(l)==2,repr(i)
1908 result=result+l[1]
1909 return result
1910
1911# Main function. It reads and parses the input and generates the
1912# various files.
1913def main():
1914
1915 src_dir=os.path.dirname(sys.argv[0])
1916 src_root=src_dir+"/.."
1917 input_name=src_dir+"/networking/packets.def"
1918
1919 content=open(input_name).read()
1920 content=strip_c_comment(content)
1921 lines=content.split("\n")
1922 lines = map(lambda x: re.sub(r"\s*#.*$", "", x), lines)
1923 lines = map(lambda x: re.sub(r"\s*//.*$", "", x), lines)
1924 lines = filter(lambda x: not re.search(r"^\s*$", x), lines)
1925 lines2=[]
1926 types=[]
1927 for i in lines:
1928 mo = re.search(r"^type\s+(\S+)\s*=\s*(.+)\s*$", i)
1929 if mo:
1930 types.append(Type(mo.group(1),mo.group(2)))
1931 else:
1932 lines2.append(i)
1933
1934 packets=[]
1935 for str in re.split("(?m)^end$","\n".join(lines2)):
1936 str=str.strip()
1937 if str:
1938 packets.append(Packet(str,types))
1939
1940
1941
1942
1943 output_h_name=sys.argv[1]
1944
1945 if output_h_name != "":
1946 if lazy_overwrite:
1947 output_h=fc_open(output_h_name+".tmp")
1948 else:
1949 output_h=fc_open(output_h_name)
1950
1951 output_h.write('''
1952#ifdef __cplusplus
1953extern "C" {
1954#endif /* __cplusplus */
1955
1956/* common */
1957#include "actions.h"
1958#include "city.h"
1959#include "disaster.h"
1960#include "unit.h"
1961
1962/* common/aicore */
1963#include "cm.h"
1964
1965''')
1966
1967 # write structs
1968 for p in packets:
1969 output_h.write(p.get_struct())
1970
1971 output_h.write(get_enum_packet(packets))
1972
1973 # write function prototypes
1974 for p in packets:
1975 output_h.write(p.get_prototypes())
1976 output_h.write('''
1977void delta_stats_report(void);
1978void delta_stats_reset(void);
1979
1980#ifdef __cplusplus
1981}
1982#endif /* __cplusplus */
1983''')
1984 output_h.close()
1985
1986
1987 output_c_name=sys.argv[2]
1988 if output_c_name != "":
1989 if lazy_overwrite:
1990 output_c=fc_open(output_c_name+".tmp")
1991 else:
1992 output_c=fc_open(output_c_name)
1993
1994 output_c.write('''
1995#ifdef HAVE_CONFIG_H
1996#include <fc_config.h>
1997#endif
1998
1999#include <string.h>
2000
2001/* utility */
2002#include "bitvector.h"
2003#include "capability.h"
2004#include "genhash.h"
2005#include "log.h"
2006#include "mem.h"
2007#include "support.h"
2008
2009/* common */
2010#include "capstr.h"
2011#include "connection.h"
2012#include "dataio.h"
2013#include "game.h"
2014
2015#include "packets.h"
2016''')
2017 output_c.write(get_packet_functional_capability(packets))
2018 output_c.write('''
2019#ifdef FREECIV_DELTA_PROTOCOL
2020static genhash_val_t hash_const(const void *vkey)
2021{
2022 return 0;
2023}
2024
2025static bool cmp_const(const void *vkey1, const void *vkey2)
2026{
2027 return TRUE;
2028}
2029#endif /* FREECIV_DELTA_PROTOCOL */
2030''')
2031
2032 if generate_stats:
2033 output_c.write('''
2034static int stats_total_sent;
2035
2036''')
2037
2038 if generate_stats:
2039 # write stats
2040 for p in packets:
2041 output_c.write(p.get_stats())
2042 # write report()
2043 output_c.write(get_report(packets))
2044 output_c.write(get_reset(packets))
2045
2046 output_c.write(get_packet_name(packets))
2047 output_c.write(get_packet_has_game_info_flag(packets))
2048
2049 # write hash, cmp, send, receive
2050 for p in packets:
2051 output_c.write(p.get_variants())
2052 output_c.write(p.get_send())
2053 output_c.write(p.get_lsend())
2054 output_c.write(p.get_dsend())
2055 output_c.write(p.get_dlsend())
2056
2057 output_c.write(get_packet_handlers_fill_initial(packets))
2058 output_c.write(get_packet_handlers_fill_capability(packets))
2059 output_c.close()
2060
2061 if lazy_overwrite:
2062 for i in [output_h_name,output_c_name]:
2063 if os.path.isfile(i):
2064 old=open(i).read()
2065 else:
2066 old=""
2067 new=open(i+".tmp").read()
2068 if old!=new:
2069 open(i,"w").write(new)
2070 os.remove(i+".tmp")
2071
2072 if sys.argv[5] != "":
2073 f=fc_open(sys.argv[5])
2074 f.write('''
2075#ifndef FC__HAND_GEN_H
2076#define FC__HAND_GEN_H
2077
2078/* utility */
2079#include "shared.h"
2080
2081/* common */
2082#include "fc_types.h"
2083#include "packets.h"
2084
2085struct connection;
2086
2087bool server_handle_packet(enum packet_type type, const void *packet,
2088 struct player *pplayer, struct connection *pconn);
2089
2090''')
2091
2092 for p in packets:
2093 if "cs" in p.dirs and not p.no_handle:
2094 a=p.name[len("packet_"):]
2095 type=a.split("_")[0]
2096 b=p.fields
2097 b=map(lambda x:"%s%s"%(x.get_handle_type(), x.name),b)
2098 b=", ".join(b)
2099 if b:
2100 b=", "+b
2101 if p.handle_via_packet:
2102 f.write('struct %s;\n'%p.name)
2103 if p.handle_per_conn:
2104 f.write('void handle_%s(struct connection *pc, const struct %s *packet);\n'%(a,p.name))
2105 else:
2106 f.write('void handle_%s(struct player *pplayer, const struct %s *packet);\n'%(a,p.name))
2107 else:
2108 if p.handle_per_conn:
2109 f.write('void handle_%s(struct connection *pc%s);\n'%(a,b))
2110 else:
2111 f.write('void handle_%s(struct player *pplayer%s);\n'%(a,b))
2112 f.write('''
2113#endif /* FC__HAND_GEN_H */
2114''')
2115 f.close()
2116
2117 if sys.argv[3] != "":
2118 f=fc_open(sys.argv[3])
2119 f.write('''
2120#ifndef FC__PACKHAND_GEN_H
2121#define FC__PACKHAND_GEN_H
2122
2123#ifdef __cplusplus
2124extern "C" {
2125#endif /* __cplusplus */
2126
2127/* utility */
2128#include "shared.h"
2129
2130/* common */
2131#include "packets.h"
2132
2133bool client_handle_packet(enum packet_type type, const void *packet);
2134
2135''')
2136 for p in packets:
2137 if "sc" not in p.dirs: continue
2138
2139 a=p.name[len("packet_"):]
2140 b=p.fields
2141 #print len(p.fields),p.name
2142 b=map(lambda x:"%s%s"%(x.get_handle_type(), x.name),b)
2143 b=", ".join(b)
2144 if not b:
2145 b="void"
2146 if p.handle_via_packet:
2147 f.write('struct %s;\n'%p.name)
2148 f.write('void handle_%s(const struct %s *packet);\n'%(a,p.name))
2149 else:
2150 f.write('void handle_%s(%s);\n'%(a,b))
2151 f.write('''
2152#ifdef __cplusplus
2153}
2154#endif /* __cplusplus */
2155
2156#endif /* FC__PACKHAND_GEN_H */
2157''')
2158 f.close()
2159
2160 if sys.argv[6] != "":
2161 f=fc_open(sys.argv[6])
2162 f.write('''
2163
2164#ifdef HAVE_CONFIG_H
2165#include <fc_config.h>
2166#endif
2167
2168/* common */
2169#include "packets.h"
2170
2171#include "hand_gen.h"
2172
2173bool server_handle_packet(enum packet_type type, const void *packet,
2174 struct player *pplayer, struct connection *pconn)
2175{
2176 switch (type) {
2177''')
2178 for p in packets:
2179 if "cs" not in p.dirs: continue
2180 if p.no_handle: continue
2181 a=p.name[len("packet_"):]
2182 c='((const struct %s *)packet)->'%p.name
2183 b=[]
2184 for x in p.fields:
2185 y="%s%s"%(c,x.name)
2186 if x.dataio_type=="worklist":
2187 y="&"+y
2188 b.append(y)
2189 b=",\n ".join(b)
2190 if b:
2191 b=",\n "+b
2192
2193 if p.handle_via_packet:
2194 if p.handle_per_conn:
2195 args="pconn, packet"
2196 else:
2197 args="pplayer, packet"
2198
2199 else:
2200 if p.handle_per_conn:
2201 args="pconn"+b
2202 else:
2203 args="pplayer"+b
2204
2205 f.write(''' case %s:
2206 handle_%s(%s);
2207 return TRUE;
2208
2209'''%(p.type,a,args))
2210 f.write(''' default:
2211 return FALSE;
2212 }
2213}
2214''')
2215 f.close()
2216
2217 if sys.argv[4] != "":
2218 f=fc_open(sys.argv[4])
2219 f.write('''
2220
2221#ifdef HAVE_CONFIG_H
2222#include <fc_config.h>
2223#endif
2224
2225/* common */
2226#include "packets.h"
2227
2228#include "packhand_gen.h"
2229
2230bool client_handle_packet(enum packet_type type, const void *packet)
2231{
2232 switch (type) {
2233''')
2234 for p in packets:
2235 if "sc" not in p.dirs: continue
2236 if p.no_handle: continue
2237 a=p.name[len("packet_"):]
2238 c='((const struct %s *)packet)->'%p.name
2239 b=[]
2240 for x in p.fields:
2241 y="%s%s"%(c,x.name)
2242 if x.dataio_type=="worklist":
2243 y="&"+y
2244 b.append(y)
2245 b=",\n ".join(b)
2246 if b:
2247 b="\n "+b
2248
2249 if p.handle_via_packet:
2250 args="packet"
2251 else:
2252 args=b
2253
2254 f.write(''' case %s:
2255 handle_%s(%s);
2256 return TRUE;
2257
2258'''%(p.type,a,args))
2259 f.write(''' default:
2260 return FALSE;
2261 }
2262}
2263''')
2264 f.close()
2265
2266main()
__init__(self, fieldinfo, typeinfo, flaginfo)
get_get_real(self, deltafragment)
get_get_wrapper(self, packet, i, deltafragment)
get_cmp_wrapper(self, i, pack)
get_put_wrapper(self, packet, i, deltafragment)
get_put_real(self, deltafragment)
get_put(self, deltafragment)
get_get(self, deltafragment)
__init__(self, alias, dest)
__init__(self, poscaps, negcaps, name, fields, packet, no)
static struct fc_sockaddr_list * list
Definition clinet.c:102
get_packet_has_game_info_flag(packets)
get_packet_handlers_fill_initial(packets)
get_packet_functional_capability(packets)
prefix(prefix, str)
get_packet_handlers_fill_capability(packets)
parse_fields(str, types)
int len
Definition packhand.c:125