Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libevent/event_rpcgen.py
39475 views
1
#!/usr/bin/env python
2
#
3
# Copyright (c) 2005-2007 Niels Provos <[email protected]>
4
# Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
5
# All rights reserved.
6
#
7
# Generates marshaling code based on libevent.
8
9
# pylint: disable=too-many-lines
10
# pylint: disable=too-many-branches
11
# pylint: disable=too-many-public-methods
12
# pylint: disable=too-many-statements
13
# pylint: disable=global-statement
14
15
# TODO:
16
# 1) propagate the arguments/options parsed by argparse down to the
17
# instantiated factory objects.
18
# 2) move the globals into a class that manages execution, including the
19
# progress outputs that go to stderr at the moment.
20
# 3) emit other languages.
21
22
import argparse
23
import re
24
import sys
25
26
_NAME = "event_rpcgen.py"
27
_VERSION = "0.1"
28
29
# Globals
30
LINE_COUNT = 0
31
32
CPPCOMMENT_RE = re.compile(r"\/\/.*$")
33
NONIDENT_RE = re.compile(r"\W")
34
PREPROCESSOR_DEF_RE = re.compile(r"^#define")
35
STRUCT_REF_RE = re.compile(r"^struct\[(?P<name>[a-zA-Z_][a-zA-Z0-9_]*)\]$")
36
STRUCT_DEF_RE = re.compile(r"^struct +[a-zA-Z_][a-zA-Z0-9_]* *{$")
37
WHITESPACE_RE = re.compile(r"\s+")
38
39
HEADER_DIRECT = []
40
CPP_DIRECT = []
41
42
QUIETLY = False
43
44
45
def declare(s):
46
if not QUIETLY:
47
print(s)
48
49
50
def TranslateList(mylist, mydict):
51
return [x % mydict for x in mylist]
52
53
54
class RpcGenError(Exception):
55
"""An Exception class for parse errors."""
56
57
def __init__(self, why): # pylint: disable=super-init-not-called
58
self.why = why
59
60
def __str__(self):
61
return str(self.why)
62
63
64
# Holds everything that makes a struct
65
class Struct(object):
66
def __init__(self, name):
67
self._name = name
68
self._entries = []
69
self._tags = {}
70
declare(" Created struct: %s" % name)
71
72
def AddEntry(self, entry):
73
if entry.Tag() in self._tags:
74
raise RpcGenError(
75
'Entry "%s" duplicates tag number %d from "%s" '
76
"around line %d"
77
% (entry.Name(), entry.Tag(), self._tags[entry.Tag()], LINE_COUNT)
78
)
79
self._entries.append(entry)
80
self._tags[entry.Tag()] = entry.Name()
81
declare(" Added entry: %s" % entry.Name())
82
83
def Name(self):
84
return self._name
85
86
def EntryTagName(self, entry):
87
"""Creates the name inside an enumeration for distinguishing data
88
types."""
89
name = "%s_%s" % (self._name, entry.Name())
90
return name.upper()
91
92
@staticmethod
93
def PrintIndented(filep, ident, code):
94
"""Takes an array, add indentation to each entry and prints it."""
95
for entry in code:
96
filep.write("%s%s\n" % (ident, entry))
97
98
99
class StructCCode(Struct):
100
""" Knows how to generate C code for a struct """
101
102
def __init__(self, name):
103
Struct.__init__(self, name)
104
105
def PrintTags(self, filep):
106
"""Prints the tag definitions for a structure."""
107
filep.write("/* Tag definition for %s */\n" % self._name)
108
filep.write("enum %s_ {\n" % self._name.lower())
109
for entry in self._entries:
110
filep.write(" %s=%d,\n" % (self.EntryTagName(entry), entry.Tag()))
111
filep.write(" %s_MAX_TAGS\n" % (self._name.upper()))
112
filep.write("};\n\n")
113
114
def PrintForwardDeclaration(self, filep):
115
filep.write("struct %s;\n" % self._name)
116
117
def PrintDeclaration(self, filep):
118
filep.write("/* Structure declaration for %s */\n" % self._name)
119
filep.write("struct %s_access_ {\n" % self._name)
120
for entry in self._entries:
121
dcl = entry.AssignDeclaration("(*%s_assign)" % entry.Name())
122
dcl.extend(entry.GetDeclaration("(*%s_get)" % entry.Name()))
123
if entry.Array():
124
dcl.extend(entry.AddDeclaration("(*%s_add)" % entry.Name()))
125
self.PrintIndented(filep, " ", dcl)
126
filep.write("};\n\n")
127
128
filep.write("struct %s {\n" % self._name)
129
filep.write(" struct %s_access_ *base;\n\n" % self._name)
130
for entry in self._entries:
131
dcl = entry.Declaration()
132
self.PrintIndented(filep, " ", dcl)
133
filep.write("\n")
134
for entry in self._entries:
135
filep.write(" ev_uint8_t %s_set;\n" % entry.Name())
136
filep.write("};\n\n")
137
138
filep.write(
139
"""struct %(name)s *%(name)s_new(void);
140
struct %(name)s *%(name)s_new_with_arg(void *);
141
void %(name)s_free(struct %(name)s *);
142
void %(name)s_clear(struct %(name)s *);
143
void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
144
int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
145
int %(name)s_complete(struct %(name)s *);
146
void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
147
const struct %(name)s *);
148
int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
149
struct %(name)s *);\n"""
150
% {"name": self._name}
151
)
152
153
# Write a setting function of every variable
154
for entry in self._entries:
155
self.PrintIndented(
156
filep, "", entry.AssignDeclaration(entry.AssignFuncName())
157
)
158
self.PrintIndented(filep, "", entry.GetDeclaration(entry.GetFuncName()))
159
if entry.Array():
160
self.PrintIndented(filep, "", entry.AddDeclaration(entry.AddFuncName()))
161
162
filep.write("/* --- %s done --- */\n\n" % self._name)
163
164
def PrintCode(self, filep):
165
filep.write(
166
"""/*
167
* Implementation of %s
168
*/
169
"""
170
% (self._name)
171
)
172
173
filep.write(
174
"""
175
static struct %(name)s_access_ %(name)s_base__ = {
176
"""
177
% {"name": self._name}
178
)
179
for entry in self._entries:
180
self.PrintIndented(filep, " ", entry.CodeBase())
181
filep.write("};\n\n")
182
183
# Creation
184
filep.write(
185
"""struct %(name)s *
186
%(name)s_new(void)
187
{
188
return %(name)s_new_with_arg(NULL);
189
}
190
191
struct %(name)s *
192
%(name)s_new_with_arg(void *unused)
193
{
194
struct %(name)s *tmp;
195
if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {
196
event_warn("%%s: malloc", __func__);
197
return (NULL);
198
}
199
tmp->base = &%(name)s_base__;
200
201
"""
202
% {"name": self._name}
203
)
204
205
for entry in self._entries:
206
self.PrintIndented(filep, " ", entry.CodeInitialize("tmp"))
207
filep.write(" tmp->%s_set = 0;\n\n" % entry.Name())
208
209
filep.write(
210
""" return (tmp);
211
}
212
213
"""
214
)
215
216
# Adding
217
for entry in self._entries:
218
if entry.Array():
219
self.PrintIndented(filep, "", entry.CodeAdd())
220
filep.write("\n")
221
222
# Assigning
223
for entry in self._entries:
224
self.PrintIndented(filep, "", entry.CodeAssign())
225
filep.write("\n")
226
227
# Getting
228
for entry in self._entries:
229
self.PrintIndented(filep, "", entry.CodeGet())
230
filep.write("\n")
231
232
# Clearing
233
filep.write(
234
"""void
235
%(name)s_clear(struct %(name)s *tmp)
236
{
237
"""
238
% {"name": self._name}
239
)
240
for entry in self._entries:
241
self.PrintIndented(filep, " ", entry.CodeClear("tmp"))
242
243
filep.write("}\n\n")
244
245
# Freeing
246
filep.write(
247
"""void
248
%(name)s_free(struct %(name)s *tmp)
249
{
250
"""
251
% {"name": self._name}
252
)
253
254
for entry in self._entries:
255
self.PrintIndented(filep, " ", entry.CodeFree("tmp"))
256
257
filep.write(
258
""" free(tmp);
259
}
260
261
"""
262
)
263
264
# Marshaling
265
filep.write(
266
"""void
267
%(name)s_marshal(struct evbuffer *evbuf, const struct %(name)s *tmp) {
268
"""
269
% {"name": self._name}
270
)
271
for entry in self._entries:
272
indent = " "
273
# Optional entries do not have to be set
274
if entry.Optional():
275
indent += " "
276
filep.write(" if (tmp->%s_set) {\n" % entry.Name())
277
self.PrintIndented(
278
filep,
279
indent,
280
entry.CodeMarshal(
281
"evbuf",
282
self.EntryTagName(entry),
283
entry.GetVarName("tmp"),
284
entry.GetVarLen("tmp"),
285
),
286
)
287
if entry.Optional():
288
filep.write(" }\n")
289
290
filep.write("}\n\n")
291
292
# Unmarshaling
293
filep.write(
294
"""int
295
%(name)s_unmarshal(struct %(name)s *tmp, struct evbuffer *evbuf)
296
{
297
ev_uint32_t tag;
298
while (evbuffer_get_length(evbuf) > 0) {
299
if (evtag_peek(evbuf, &tag) == -1)
300
return (-1);
301
switch (tag) {
302
303
"""
304
% {"name": self._name}
305
)
306
for entry in self._entries:
307
filep.write(" case %s:\n" % (self.EntryTagName(entry)))
308
if not entry.Array():
309
filep.write(
310
""" if (tmp->%s_set)
311
return (-1);
312
"""
313
% (entry.Name())
314
)
315
316
self.PrintIndented(
317
filep,
318
" ",
319
entry.CodeUnmarshal(
320
"evbuf",
321
self.EntryTagName(entry),
322
entry.GetVarName("tmp"),
323
entry.GetVarLen("tmp"),
324
),
325
)
326
327
filep.write(
328
""" tmp->%s_set = 1;
329
break;
330
"""
331
% (entry.Name())
332
)
333
filep.write(
334
""" default:
335
return -1;
336
}
337
}
338
339
"""
340
)
341
# Check if it was decoded completely
342
filep.write(
343
""" if (%(name)s_complete(tmp) == -1)
344
return (-1);
345
return (0);
346
}
347
"""
348
% {"name": self._name}
349
)
350
351
# Checking if a structure has all the required data
352
filep.write(
353
"""
354
int
355
%(name)s_complete(struct %(name)s *msg)
356
{
357
"""
358
% {"name": self._name}
359
)
360
for entry in self._entries:
361
if not entry.Optional():
362
code = [
363
"""if (!msg->%(name)s_set)
364
return (-1);"""
365
]
366
code = TranslateList(code, entry.GetTranslation())
367
self.PrintIndented(filep, " ", code)
368
369
self.PrintIndented(
370
filep, " ", entry.CodeComplete("msg", entry.GetVarName("msg"))
371
)
372
filep.write(
373
""" return (0);
374
}
375
"""
376
)
377
378
# Complete message unmarshaling
379
filep.write(
380
"""
381
int
382
evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t need_tag,
383
struct %(name)s *msg)
384
{
385
ev_uint32_t tag;
386
int res = -1;
387
388
struct evbuffer *tmp = evbuffer_new();
389
390
if (evtag_unmarshal(evbuf, &tag, tmp) == -1 || tag != need_tag)
391
goto error;
392
393
if (%(name)s_unmarshal(msg, tmp) == -1)
394
goto error;
395
396
res = 0;
397
398
error:
399
evbuffer_free(tmp);
400
return (res);
401
}
402
"""
403
% {"name": self._name}
404
)
405
406
# Complete message marshaling
407
filep.write(
408
"""
409
void
410
evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag,
411
const struct %(name)s *msg)
412
{
413
struct evbuffer *buf_ = evbuffer_new();
414
assert(buf_ != NULL);
415
%(name)s_marshal(buf_, msg);
416
evtag_marshal_buffer(evbuf, tag, buf_);
417
evbuffer_free(buf_);
418
}
419
420
"""
421
% {"name": self._name}
422
)
423
424
425
class Entry(object):
426
def __init__(self, ent_type, name, tag):
427
self._type = ent_type
428
self._name = name
429
self._tag = int(tag)
430
self._ctype = ent_type
431
self._optional = False
432
self._can_be_array = False
433
self._array = False
434
self._line_count = -1
435
self._struct = None
436
self._refname = None
437
438
self._optpointer = True
439
self._optaddarg = True
440
441
@staticmethod
442
def GetInitializer():
443
raise NotImplementedError("Entry does not provide an initializer")
444
445
def SetStruct(self, struct):
446
self._struct = struct
447
448
def LineCount(self):
449
assert self._line_count != -1
450
return self._line_count
451
452
def SetLineCount(self, number):
453
self._line_count = number
454
455
def Array(self):
456
return self._array
457
458
def Optional(self):
459
return self._optional
460
461
def Tag(self):
462
return self._tag
463
464
def Name(self):
465
return self._name
466
467
def Type(self):
468
return self._type
469
470
def MakeArray(self):
471
self._array = True
472
473
def MakeOptional(self):
474
self._optional = True
475
476
def Verify(self):
477
if self.Array() and not self._can_be_array:
478
raise RpcGenError(
479
'Entry "%s" cannot be created as an array '
480
"around line %d" % (self._name, self.LineCount())
481
)
482
if not self._struct:
483
raise RpcGenError(
484
'Entry "%s" does not know which struct it belongs to '
485
"around line %d" % (self._name, self.LineCount())
486
)
487
if self._optional and self._array:
488
raise RpcGenError(
489
'Entry "%s" has illegal combination of optional and array '
490
"around line %d" % (self._name, self.LineCount())
491
)
492
493
def GetTranslation(self, extradict=None):
494
if extradict is None:
495
extradict = {}
496
mapping = {
497
"parent_name": self._struct.Name(),
498
"name": self._name,
499
"ctype": self._ctype,
500
"refname": self._refname,
501
"optpointer": self._optpointer and "*" or "",
502
"optreference": self._optpointer and "&" or "",
503
"optaddarg": self._optaddarg and ", const %s value" % self._ctype or "",
504
}
505
for (k, v) in list(extradict.items()):
506
mapping[k] = v
507
508
return mapping
509
510
def GetVarName(self, var):
511
return "%(var)s->%(name)s_data" % self.GetTranslation({"var": var})
512
513
def GetVarLen(self, _var):
514
return "sizeof(%s)" % self._ctype
515
516
def GetFuncName(self):
517
return "%s_%s_get" % (self._struct.Name(), self._name)
518
519
def GetDeclaration(self, funcname):
520
code = [
521
"int %s(struct %s *, %s *);" % (funcname, self._struct.Name(), self._ctype)
522
]
523
return code
524
525
def CodeGet(self):
526
code = """int
527
%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, %(ctype)s *value)
528
{
529
if (msg->%(name)s_set != 1)
530
return (-1);
531
*value = msg->%(name)s_data;
532
return (0);
533
}"""
534
code = code % self.GetTranslation()
535
return code.split("\n")
536
537
def AssignFuncName(self):
538
return "%s_%s_assign" % (self._struct.Name(), self._name)
539
540
def AddFuncName(self):
541
return "%s_%s_add" % (self._struct.Name(), self._name)
542
543
def AssignDeclaration(self, funcname):
544
code = [
545
"int %s(struct %s *, const %s);"
546
% (funcname, self._struct.Name(), self._ctype)
547
]
548
return code
549
550
def CodeAssign(self):
551
code = [
552
"int",
553
"%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,"
554
" const %(ctype)s value)",
555
"{",
556
" msg->%(name)s_set = 1;",
557
" msg->%(name)s_data = value;",
558
" return (0);",
559
"}",
560
]
561
code = "\n".join(code)
562
code = code % self.GetTranslation()
563
return code.split("\n")
564
565
def CodeClear(self, structname):
566
code = ["%s->%s_set = 0;" % (structname, self.Name())]
567
568
return code
569
570
@staticmethod
571
def CodeComplete(_structname, _var_name):
572
return []
573
574
@staticmethod
575
def CodeFree(_name):
576
return []
577
578
def CodeBase(self):
579
code = ["%(parent_name)s_%(name)s_assign,", "%(parent_name)s_%(name)s_get,"]
580
if self.Array():
581
code.append("%(parent_name)s_%(name)s_add,")
582
583
code = "\n".join(code)
584
code = code % self.GetTranslation()
585
return code.split("\n")
586
587
588
class EntryBytes(Entry):
589
def __init__(self, ent_type, name, tag, length):
590
# Init base class
591
super(EntryBytes, self).__init__(ent_type, name, tag)
592
593
self._length = length
594
self._ctype = "ev_uint8_t"
595
596
@staticmethod
597
def GetInitializer():
598
return "NULL"
599
600
def GetVarLen(self, _var):
601
return "(%s)" % self._length
602
603
@staticmethod
604
def CodeArrayAdd(varname, _value):
605
# XXX: copy here
606
return ["%(varname)s = NULL;" % {"varname": varname}]
607
608
def GetDeclaration(self, funcname):
609
code = [
610
"int %s(struct %s *, %s **);" % (funcname, self._struct.Name(), self._ctype)
611
]
612
return code
613
614
def AssignDeclaration(self, funcname):
615
code = [
616
"int %s(struct %s *, const %s *);"
617
% (funcname, self._struct.Name(), self._ctype)
618
]
619
return code
620
621
def Declaration(self):
622
dcl = ["ev_uint8_t %s_data[%s];" % (self._name, self._length)]
623
624
return dcl
625
626
def CodeGet(self):
627
name = self._name
628
code = [
629
"int",
630
"%s_%s_get(struct %s *msg, %s **value)"
631
% (self._struct.Name(), name, self._struct.Name(), self._ctype),
632
"{",
633
" if (msg->%s_set != 1)" % name,
634
" return (-1);",
635
" *value = msg->%s_data;" % name,
636
" return (0);",
637
"}",
638
]
639
return code
640
641
def CodeAssign(self):
642
name = self._name
643
code = [
644
"int",
645
"%s_%s_assign(struct %s *msg, const %s *value)"
646
% (self._struct.Name(), name, self._struct.Name(), self._ctype),
647
"{",
648
" msg->%s_set = 1;" % name,
649
" memcpy(msg->%s_data, value, %s);" % (name, self._length),
650
" return (0);",
651
"}",
652
]
653
return code
654
655
def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
656
code = [
657
"if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, "
658
"%(var)s, %(varlen)s) == -1) {",
659
' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
660
" return (-1);",
661
"}",
662
]
663
return TranslateList(
664
code,
665
self.GetTranslation(
666
{"var": var_name, "varlen": var_len, "buf": buf, "tag": tag_name}
667
),
668
)
669
670
@staticmethod
671
def CodeMarshal(buf, tag_name, var_name, var_len):
672
code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
673
return code
674
675
def CodeClear(self, structname):
676
code = [
677
"%s->%s_set = 0;" % (structname, self.Name()),
678
"memset(%s->%s_data, 0, sizeof(%s->%s_data));"
679
% (structname, self._name, structname, self._name),
680
]
681
682
return code
683
684
def CodeInitialize(self, name):
685
code = [
686
"memset(%s->%s_data, 0, sizeof(%s->%s_data));"
687
% (name, self._name, name, self._name)
688
]
689
return code
690
691
def Verify(self):
692
if not self._length:
693
raise RpcGenError(
694
'Entry "%s" needs a length '
695
"around line %d" % (self._name, self.LineCount())
696
)
697
698
super(EntryBytes, self).Verify()
699
700
701
class EntryInt(Entry):
702
def __init__(self, ent_type, name, tag, bits=32):
703
# Init base class
704
super(EntryInt, self).__init__(ent_type, name, tag)
705
706
self._can_be_array = True
707
if bits == 32:
708
self._ctype = "ev_uint32_t"
709
self._marshal_type = "int"
710
if bits == 64:
711
self._ctype = "ev_uint64_t"
712
self._marshal_type = "int64"
713
714
@staticmethod
715
def GetInitializer():
716
return "0"
717
718
@staticmethod
719
def CodeArrayFree(_var):
720
return []
721
722
@staticmethod
723
def CodeArrayAssign(varname, srcvar):
724
return ["%(varname)s = %(srcvar)s;" % {"varname": varname, "srcvar": srcvar}]
725
726
@staticmethod
727
def CodeArrayAdd(varname, value):
728
"""Returns a new entry of this type."""
729
return ["%(varname)s = %(value)s;" % {"varname": varname, "value": value}]
730
731
def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
732
code = [
733
"if (evtag_unmarshal_%(ma)s(%(buf)s, %(tag)s, &%(var)s) == -1) {",
734
' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
735
" return (-1);",
736
"}",
737
]
738
code = "\n".join(code) % self.GetTranslation(
739
{"ma": self._marshal_type, "buf": buf, "tag": tag_name, "var": var_name}
740
)
741
return code.split("\n")
742
743
def CodeMarshal(self, buf, tag_name, var_name, _var_len):
744
code = [
745
"evtag_marshal_%s(%s, %s, %s);"
746
% (self._marshal_type, buf, tag_name, var_name)
747
]
748
return code
749
750
def Declaration(self):
751
dcl = ["%s %s_data;" % (self._ctype, self._name)]
752
753
return dcl
754
755
def CodeInitialize(self, name):
756
code = ["%s->%s_data = 0;" % (name, self._name)]
757
return code
758
759
760
class EntryString(Entry):
761
def __init__(self, ent_type, name, tag):
762
# Init base class
763
super(EntryString, self).__init__(ent_type, name, tag)
764
765
self._can_be_array = True
766
self._ctype = "char *"
767
768
@staticmethod
769
def GetInitializer():
770
return "NULL"
771
772
@staticmethod
773
def CodeArrayFree(varname):
774
code = ["if (%(var)s != NULL) free(%(var)s);"]
775
776
return TranslateList(code, {"var": varname})
777
778
@staticmethod
779
def CodeArrayAssign(varname, srcvar):
780
code = [
781
"if (%(var)s != NULL)",
782
" free(%(var)s);",
783
"%(var)s = strdup(%(srcvar)s);",
784
"if (%(var)s == NULL) {",
785
' event_warnx("%%s: strdup", __func__);',
786
" return (-1);",
787
"}",
788
]
789
790
return TranslateList(code, {"var": varname, "srcvar": srcvar})
791
792
@staticmethod
793
def CodeArrayAdd(varname, value):
794
code = [
795
"if (%(value)s != NULL) {",
796
" %(var)s = strdup(%(value)s);",
797
" if (%(var)s == NULL) {",
798
" goto error;",
799
" }",
800
"} else {",
801
" %(var)s = NULL;",
802
"}",
803
]
804
805
return TranslateList(code, {"var": varname, "value": value})
806
807
def GetVarLen(self, var):
808
return "strlen(%s)" % self.GetVarName(var)
809
810
@staticmethod
811
def CodeMakeInitalize(varname):
812
return "%(varname)s = NULL;" % {"varname": varname}
813
814
def CodeAssign(self):
815
code = """int
816
%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
817
const %(ctype)s value)
818
{
819
if (msg->%(name)s_data != NULL)
820
free(msg->%(name)s_data);
821
if ((msg->%(name)s_data = strdup(value)) == NULL)
822
return (-1);
823
msg->%(name)s_set = 1;
824
return (0);
825
}""" % (
826
self.GetTranslation()
827
)
828
829
return code.split("\n")
830
831
def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
832
code = [
833
"if (evtag_unmarshal_string(%(buf)s, %(tag)s, &%(var)s) == -1) {",
834
' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
835
" return (-1);",
836
"}",
837
]
838
code = "\n".join(code) % self.GetTranslation(
839
{"buf": buf, "tag": tag_name, "var": var_name}
840
)
841
return code.split("\n")
842
843
@staticmethod
844
def CodeMarshal(buf, tag_name, var_name, _var_len):
845
code = ["evtag_marshal_string(%s, %s, %s);" % (buf, tag_name, var_name)]
846
return code
847
848
def CodeClear(self, structname):
849
code = [
850
"if (%s->%s_set == 1) {" % (structname, self.Name()),
851
" free(%s->%s_data);" % (structname, self.Name()),
852
" %s->%s_data = NULL;" % (structname, self.Name()),
853
" %s->%s_set = 0;" % (structname, self.Name()),
854
"}",
855
]
856
857
return code
858
859
def CodeInitialize(self, name):
860
code = ["%s->%s_data = NULL;" % (name, self._name)]
861
return code
862
863
def CodeFree(self, name):
864
code = [
865
"if (%s->%s_data != NULL)" % (name, self._name),
866
" free (%s->%s_data);" % (name, self._name),
867
]
868
869
return code
870
871
def Declaration(self):
872
dcl = ["char *%s_data;" % self._name]
873
874
return dcl
875
876
877
class EntryStruct(Entry):
878
def __init__(self, ent_type, name, tag, refname):
879
# Init base class
880
super(EntryStruct, self).__init__(ent_type, name, tag)
881
882
self._optpointer = False
883
self._can_be_array = True
884
self._refname = refname
885
self._ctype = "struct %s*" % refname
886
self._optaddarg = False
887
888
def GetInitializer(self):
889
return "NULL"
890
891
def GetVarLen(self, _var):
892
return "-1"
893
894
def CodeArrayAdd(self, varname, _value):
895
code = [
896
"%(varname)s = %(refname)s_new();",
897
"if (%(varname)s == NULL)",
898
" goto error;",
899
]
900
901
return TranslateList(code, self.GetTranslation({"varname": varname}))
902
903
def CodeArrayFree(self, var):
904
code = ["%(refname)s_free(%(var)s);" % self.GetTranslation({"var": var})]
905
return code
906
907
def CodeArrayAssign(self, var, srcvar):
908
code = [
909
"int had_error = 0;",
910
"struct evbuffer *tmp = NULL;",
911
"%(refname)s_clear(%(var)s);",
912
"if ((tmp = evbuffer_new()) == NULL) {",
913
' event_warn("%%s: evbuffer_new()", __func__);',
914
" had_error = 1;",
915
" goto done;",
916
"}",
917
"%(refname)s_marshal(tmp, %(srcvar)s);",
918
"if (%(refname)s_unmarshal(%(var)s, tmp) == -1) {",
919
' event_warnx("%%s: %(refname)s_unmarshal", __func__);',
920
" had_error = 1;",
921
" goto done;",
922
"}",
923
"done:",
924
"if (tmp != NULL)",
925
" evbuffer_free(tmp);",
926
"if (had_error) {",
927
" %(refname)s_clear(%(var)s);",
928
" return (-1);",
929
"}",
930
]
931
932
return TranslateList(code, self.GetTranslation({"var": var, "srcvar": srcvar}))
933
934
def CodeGet(self):
935
name = self._name
936
code = [
937
"int",
938
"%s_%s_get(struct %s *msg, %s *value)"
939
% (self._struct.Name(), name, self._struct.Name(), self._ctype),
940
"{",
941
" if (msg->%s_set != 1) {" % name,
942
" msg->%s_data = %s_new();" % (name, self._refname),
943
" if (msg->%s_data == NULL)" % name,
944
" return (-1);",
945
" msg->%s_set = 1;" % name,
946
" }",
947
" *value = msg->%s_data;" % name,
948
" return (0);",
949
"}",
950
]
951
return code
952
953
def CodeAssign(self):
954
code = (
955
"""int
956
%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
957
const %(ctype)s value)
958
{
959
struct evbuffer *tmp = NULL;
960
if (msg->%(name)s_set) {
961
%(refname)s_clear(msg->%(name)s_data);
962
msg->%(name)s_set = 0;
963
} else {
964
msg->%(name)s_data = %(refname)s_new();
965
if (msg->%(name)s_data == NULL) {
966
event_warn("%%s: %(refname)s_new()", __func__);
967
goto error;
968
}
969
}
970
if ((tmp = evbuffer_new()) == NULL) {
971
event_warn("%%s: evbuffer_new()", __func__);
972
goto error;
973
}
974
%(refname)s_marshal(tmp, value);
975
if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
976
event_warnx("%%s: %(refname)s_unmarshal", __func__);
977
goto error;
978
}
979
msg->%(name)s_set = 1;
980
evbuffer_free(tmp);
981
return (0);
982
error:
983
if (tmp != NULL)
984
evbuffer_free(tmp);
985
if (msg->%(name)s_data != NULL) {
986
%(refname)s_free(msg->%(name)s_data);
987
msg->%(name)s_data = NULL;
988
}
989
return (-1);
990
}"""
991
% self.GetTranslation()
992
)
993
return code.split("\n")
994
995
def CodeComplete(self, structname, var_name):
996
code = [
997
"if (%(structname)s->%(name)s_set && "
998
"%(refname)s_complete(%(var)s) == -1)",
999
" return (-1);",
1000
]
1001
1002
return TranslateList(
1003
code, self.GetTranslation({"structname": structname, "var": var_name})
1004
)
1005
1006
def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
1007
code = [
1008
"%(var)s = %(refname)s_new();",
1009
"if (%(var)s == NULL)",
1010
" return (-1);",
1011
"if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag)s, ",
1012
" %(var)s) == -1) {",
1013
' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
1014
" return (-1);",
1015
"}",
1016
]
1017
code = "\n".join(code) % self.GetTranslation(
1018
{"buf": buf, "tag": tag_name, "var": var_name}
1019
)
1020
return code.split("\n")
1021
1022
def CodeMarshal(self, buf, tag_name, var_name, _var_len):
1023
code = [
1024
"evtag_marshal_%s(%s, %s, %s);" % (self._refname, buf, tag_name, var_name)
1025
]
1026
return code
1027
1028
def CodeClear(self, structname):
1029
code = [
1030
"if (%s->%s_set == 1) {" % (structname, self.Name()),
1031
" %s_free(%s->%s_data);" % (self._refname, structname, self.Name()),
1032
" %s->%s_data = NULL;" % (structname, self.Name()),
1033
" %s->%s_set = 0;" % (structname, self.Name()),
1034
"}",
1035
]
1036
1037
return code
1038
1039
def CodeInitialize(self, name):
1040
code = ["%s->%s_data = NULL;" % (name, self._name)]
1041
return code
1042
1043
def CodeFree(self, name):
1044
code = [
1045
"if (%s->%s_data != NULL)" % (name, self._name),
1046
" %s_free(%s->%s_data);" % (self._refname, name, self._name),
1047
]
1048
1049
return code
1050
1051
def Declaration(self):
1052
dcl = ["%s %s_data;" % (self._ctype, self._name)]
1053
1054
return dcl
1055
1056
1057
class EntryVarBytes(Entry):
1058
def __init__(self, ent_type, name, tag):
1059
# Init base class
1060
super(EntryVarBytes, self).__init__(ent_type, name, tag)
1061
1062
self._ctype = "ev_uint8_t *"
1063
1064
@staticmethod
1065
def GetInitializer():
1066
return "NULL"
1067
1068
def GetVarLen(self, var):
1069
return "%(var)s->%(name)s_length" % self.GetTranslation({"var": var})
1070
1071
@staticmethod
1072
def CodeArrayAdd(varname, _value):
1073
# xxx: copy
1074
return ["%(varname)s = NULL;" % {"varname": varname}]
1075
1076
def GetDeclaration(self, funcname):
1077
code = [
1078
"int %s(struct %s *, %s *, ev_uint32_t *);"
1079
% (funcname, self._struct.Name(), self._ctype)
1080
]
1081
return code
1082
1083
def AssignDeclaration(self, funcname):
1084
code = [
1085
"int %s(struct %s *, const %s, ev_uint32_t);"
1086
% (funcname, self._struct.Name(), self._ctype)
1087
]
1088
return code
1089
1090
def CodeAssign(self):
1091
name = self._name
1092
code = [
1093
"int",
1094
"%s_%s_assign(struct %s *msg, "
1095
"const %s value, ev_uint32_t len)"
1096
% (self._struct.Name(), name, self._struct.Name(), self._ctype),
1097
"{",
1098
" if (msg->%s_data != NULL)" % name,
1099
" free (msg->%s_data);" % name,
1100
" msg->%s_data = malloc(len);" % name,
1101
" if (msg->%s_data == NULL)" % name,
1102
" return (-1);",
1103
" msg->%s_set = 1;" % name,
1104
" msg->%s_length = len;" % name,
1105
" memcpy(msg->%s_data, value, len);" % name,
1106
" return (0);",
1107
"}",
1108
]
1109
return code
1110
1111
def CodeGet(self):
1112
name = self._name
1113
code = [
1114
"int",
1115
"%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)"
1116
% (self._struct.Name(), name, self._struct.Name(), self._ctype),
1117
"{",
1118
" if (msg->%s_set != 1)" % name,
1119
" return (-1);",
1120
" *value = msg->%s_data;" % name,
1121
" *plen = msg->%s_length;" % name,
1122
" return (0);",
1123
"}",
1124
]
1125
return code
1126
1127
def CodeUnmarshal(self, buf, tag_name, var_name, var_len):
1128
code = [
1129
"if (evtag_payload_length(%(buf)s, &%(varlen)s) == -1)",
1130
" return (-1);",
1131
# We do not want DoS opportunities
1132
"if (%(varlen)s > evbuffer_get_length(%(buf)s))",
1133
" return (-1);",
1134
"if ((%(var)s = malloc(%(varlen)s)) == NULL)",
1135
" return (-1);",
1136
"if (evtag_unmarshal_fixed(%(buf)s, %(tag)s, %(var)s, "
1137
"%(varlen)s) == -1) {",
1138
' event_warnx("%%s: failed to unmarshal %(name)s", __func__);',
1139
" return (-1);",
1140
"}",
1141
]
1142
code = "\n".join(code) % self.GetTranslation(
1143
{"buf": buf, "tag": tag_name, "var": var_name, "varlen": var_len}
1144
)
1145
return code.split("\n")
1146
1147
@staticmethod
1148
def CodeMarshal(buf, tag_name, var_name, var_len):
1149
code = ["evtag_marshal(%s, %s, %s, %s);" % (buf, tag_name, var_name, var_len)]
1150
return code
1151
1152
def CodeClear(self, structname):
1153
code = [
1154
"if (%s->%s_set == 1) {" % (structname, self.Name()),
1155
" free (%s->%s_data);" % (structname, self.Name()),
1156
" %s->%s_data = NULL;" % (structname, self.Name()),
1157
" %s->%s_length = 0;" % (structname, self.Name()),
1158
" %s->%s_set = 0;" % (structname, self.Name()),
1159
"}",
1160
]
1161
1162
return code
1163
1164
def CodeInitialize(self, name):
1165
code = [
1166
"%s->%s_data = NULL;" % (name, self._name),
1167
"%s->%s_length = 0;" % (name, self._name),
1168
]
1169
return code
1170
1171
def CodeFree(self, name):
1172
code = [
1173
"if (%s->%s_data != NULL)" % (name, self._name),
1174
" free(%s->%s_data);" % (name, self._name),
1175
]
1176
1177
return code
1178
1179
def Declaration(self):
1180
dcl = [
1181
"ev_uint8_t *%s_data;" % self._name,
1182
"ev_uint32_t %s_length;" % self._name,
1183
]
1184
1185
return dcl
1186
1187
1188
class EntryArray(Entry):
1189
_index = None
1190
1191
def __init__(self, entry):
1192
# Init base class
1193
super(EntryArray, self).__init__(entry._type, entry._name, entry._tag)
1194
1195
self._entry = entry
1196
self._refname = entry._refname
1197
self._ctype = self._entry._ctype
1198
self._optional = True
1199
self._optpointer = self._entry._optpointer
1200
self._optaddarg = self._entry._optaddarg
1201
1202
# provide a new function for accessing the variable name
1203
def GetVarName(var_name):
1204
return "%(var)s->%(name)s_data[%(index)s]" % self._entry.GetTranslation(
1205
{"var": var_name, "index": self._index}
1206
)
1207
1208
self._entry.GetVarName = GetVarName
1209
1210
def GetInitializer(self):
1211
return "NULL"
1212
1213
def GetVarName(self, var):
1214
return var
1215
1216
def GetVarLen(self, _var_name):
1217
return "-1"
1218
1219
def GetDeclaration(self, funcname):
1220
"""Allows direct access to elements of the array."""
1221
code = [
1222
"int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);"
1223
% self.GetTranslation({"funcname": funcname})
1224
]
1225
return code
1226
1227
def AssignDeclaration(self, funcname):
1228
code = [
1229
"int %s(struct %s *, int, const %s);"
1230
% (funcname, self._struct.Name(), self._ctype)
1231
]
1232
return code
1233
1234
def AddDeclaration(self, funcname):
1235
code = [
1236
"%(ctype)s %(optpointer)s "
1237
"%(funcname)s(struct %(parent_name)s *msg%(optaddarg)s);"
1238
% self.GetTranslation({"funcname": funcname})
1239
]
1240
return code
1241
1242
def CodeGet(self):
1243
code = """int
1244
%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
1245
%(ctype)s *value)
1246
{
1247
if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
1248
return (-1);
1249
*value = msg->%(name)s_data[offset];
1250
return (0);
1251
}
1252
""" % (
1253
self.GetTranslation()
1254
)
1255
1256
return code.splitlines()
1257
1258
def CodeAssign(self):
1259
code = [
1260
"int",
1261
"%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,",
1262
" const %(ctype)s value)",
1263
"{",
1264
" if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)",
1265
" return (-1);",
1266
"",
1267
" {",
1268
]
1269
code = TranslateList(code, self.GetTranslation())
1270
1271
codearrayassign = self._entry.CodeArrayAssign(
1272
"msg->%(name)s_data[off]" % self.GetTranslation(), "value"
1273
)
1274
code += [" " + x for x in codearrayassign]
1275
1276
code += TranslateList([" }", " return (0);", "}"], self.GetTranslation())
1277
1278
return code
1279
1280
def CodeAdd(self):
1281
codearrayadd = self._entry.CodeArrayAdd(
1282
"msg->%(name)s_data[msg->%(name)s_length - 1]" % self.GetTranslation(),
1283
"value",
1284
)
1285
code = [
1286
"static int",
1287
"%(parent_name)s_%(name)s_expand_to_hold_more("
1288
"struct %(parent_name)s *msg)",
1289
"{",
1290
" int tobe_allocated = msg->%(name)s_num_allocated;",
1291
" %(ctype)s* new_data = NULL;",
1292
" tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;",
1293
" new_data = (%(ctype)s*) realloc(msg->%(name)s_data,",
1294
" tobe_allocated * sizeof(%(ctype)s));",
1295
" if (new_data == NULL)",
1296
" return -1;",
1297
" msg->%(name)s_data = new_data;",
1298
" msg->%(name)s_num_allocated = tobe_allocated;",
1299
" return 0;",
1300
"}",
1301
"",
1302
"%(ctype)s %(optpointer)s",
1303
"%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg%(optaddarg)s)",
1304
"{",
1305
" if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {",
1306
" if (%(parent_name)s_%(name)s_expand_to_hold_more(msg)<0)",
1307
" goto error;",
1308
" }",
1309
]
1310
1311
code = TranslateList(code, self.GetTranslation())
1312
1313
code += [" " + x for x in codearrayadd]
1314
1315
code += TranslateList(
1316
[
1317
" msg->%(name)s_set = 1;",
1318
" return %(optreference)s(msg->%(name)s_data["
1319
"msg->%(name)s_length - 1]);",
1320
"error:",
1321
" --msg->%(name)s_length;",
1322
" return (NULL);",
1323
"}",
1324
],
1325
self.GetTranslation(),
1326
)
1327
1328
return code
1329
1330
def CodeComplete(self, structname, var_name):
1331
self._index = "i"
1332
tmp = self._entry.CodeComplete(structname, self._entry.GetVarName(var_name))
1333
# skip the whole loop if there is nothing to check
1334
if not tmp:
1335
return []
1336
1337
translate = self.GetTranslation({"structname": structname})
1338
code = [
1339
"{",
1340
" int i;",
1341
" for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
1342
]
1343
1344
code = TranslateList(code, translate)
1345
1346
code += [" " + x for x in tmp]
1347
1348
code += [" }", "}"]
1349
1350
return code
1351
1352
def CodeUnmarshal(self, buf, tag_name, var_name, _var_len):
1353
translate = self.GetTranslation(
1354
{
1355
"var": var_name,
1356
"buf": buf,
1357
"tag": tag_name,
1358
"init": self._entry.GetInitializer(),
1359
}
1360
)
1361
code = [
1362
"if (%(var)s->%(name)s_length >= %(var)s->%(name)s_num_allocated &&",
1363
" %(parent_name)s_%(name)s_expand_to_hold_more(%(var)s) < 0) {",
1364
' puts("HEY NOW");',
1365
" return (-1);",
1366
"}",
1367
]
1368
1369
# the unmarshal code directly returns
1370
code = TranslateList(code, translate)
1371
1372
self._index = "%(var)s->%(name)s_length" % translate
1373
code += self._entry.CodeUnmarshal(
1374
buf,
1375
tag_name,
1376
self._entry.GetVarName(var_name),
1377
self._entry.GetVarLen(var_name),
1378
)
1379
1380
code += ["++%(var)s->%(name)s_length;" % translate]
1381
1382
return code
1383
1384
def CodeMarshal(self, buf, tag_name, var_name, _var_len):
1385
code = ["{", " int i;", " for (i = 0; i < %(var)s->%(name)s_length; ++i) {"]
1386
1387
self._index = "i"
1388
code += self._entry.CodeMarshal(
1389
buf,
1390
tag_name,
1391
self._entry.GetVarName(var_name),
1392
self._entry.GetVarLen(var_name),
1393
)
1394
code += [" }", "}"]
1395
1396
code = "\n".join(code) % self.GetTranslation({"var": var_name})
1397
1398
return code.split("\n")
1399
1400
def CodeClear(self, structname):
1401
translate = self.GetTranslation({"structname": structname})
1402
codearrayfree = self._entry.CodeArrayFree(
1403
"%(structname)s->%(name)s_data[i]"
1404
% self.GetTranslation({"structname": structname})
1405
)
1406
1407
code = ["if (%(structname)s->%(name)s_set == 1) {"]
1408
1409
if codearrayfree:
1410
code += [
1411
" int i;",
1412
" for (i = 0; i < %(structname)s->%(name)s_length; ++i) {",
1413
]
1414
1415
code = TranslateList(code, translate)
1416
1417
if codearrayfree:
1418
code += [" " + x for x in codearrayfree]
1419
code += [" }"]
1420
1421
code += TranslateList(
1422
[
1423
" free(%(structname)s->%(name)s_data);",
1424
" %(structname)s->%(name)s_data = NULL;",
1425
" %(structname)s->%(name)s_set = 0;",
1426
" %(structname)s->%(name)s_length = 0;",
1427
" %(structname)s->%(name)s_num_allocated = 0;",
1428
"}",
1429
],
1430
translate,
1431
)
1432
1433
return code
1434
1435
def CodeInitialize(self, name):
1436
code = [
1437
"%s->%s_data = NULL;" % (name, self._name),
1438
"%s->%s_length = 0;" % (name, self._name),
1439
"%s->%s_num_allocated = 0;" % (name, self._name),
1440
]
1441
return code
1442
1443
def CodeFree(self, structname):
1444
code = self.CodeClear(structname)
1445
1446
code += TranslateList(
1447
["free(%(structname)s->%(name)s_data);"],
1448
self.GetTranslation({"structname": structname}),
1449
)
1450
1451
return code
1452
1453
def Declaration(self):
1454
dcl = [
1455
"%s *%s_data;" % (self._ctype, self._name),
1456
"int %s_length;" % self._name,
1457
"int %s_num_allocated;" % self._name,
1458
]
1459
1460
return dcl
1461
1462
1463
def NormalizeLine(line):
1464
1465
line = CPPCOMMENT_RE.sub("", line)
1466
line = line.strip()
1467
line = WHITESPACE_RE.sub(" ", line)
1468
1469
return line
1470
1471
1472
ENTRY_NAME_RE = re.compile(r"(?P<name>[^\[\]]+)(\[(?P<fixed_length>.*)\])?")
1473
ENTRY_TAG_NUMBER_RE = re.compile(r"(0x)?\d+", re.I)
1474
1475
1476
def ProcessOneEntry(factory, newstruct, entry):
1477
optional = False
1478
array = False
1479
entry_type = ""
1480
name = ""
1481
tag = ""
1482
tag_set = None
1483
separator = ""
1484
fixed_length = ""
1485
1486
for token in entry.split(" "):
1487
if not entry_type:
1488
if not optional and token == "optional":
1489
optional = True
1490
continue
1491
1492
if not array and token == "array":
1493
array = True
1494
continue
1495
1496
if not entry_type:
1497
entry_type = token
1498
continue
1499
1500
if not name:
1501
res = ENTRY_NAME_RE.match(token)
1502
if not res:
1503
raise RpcGenError(
1504
r"""Cannot parse name: "%s" around line %d""" % (entry, LINE_COUNT)
1505
)
1506
name = res.group("name")
1507
fixed_length = res.group("fixed_length")
1508
continue
1509
1510
if not separator:
1511
separator = token
1512
if separator != "=":
1513
raise RpcGenError(
1514
r'''Expected "=" after name "%s" got "%s"''' % (name, token)
1515
)
1516
continue
1517
1518
if not tag_set:
1519
tag_set = 1
1520
if not ENTRY_TAG_NUMBER_RE.match(token):
1521
raise RpcGenError(r'''Expected tag number: "%s"''' % (entry))
1522
tag = int(token, 0)
1523
continue
1524
1525
raise RpcGenError(r'''Cannot parse "%s"''' % (entry))
1526
1527
if not tag_set:
1528
raise RpcGenError(r'''Need tag number: "%s"''' % (entry))
1529
1530
# Create the right entry
1531
if entry_type == "bytes":
1532
if fixed_length:
1533
newentry = factory.EntryBytes(entry_type, name, tag, fixed_length)
1534
else:
1535
newentry = factory.EntryVarBytes(entry_type, name, tag)
1536
elif entry_type == "int" and not fixed_length:
1537
newentry = factory.EntryInt(entry_type, name, tag)
1538
elif entry_type == "int64" and not fixed_length:
1539
newentry = factory.EntryInt(entry_type, name, tag, bits=64)
1540
elif entry_type == "string" and not fixed_length:
1541
newentry = factory.EntryString(entry_type, name, tag)
1542
else:
1543
res = STRUCT_REF_RE.match(entry_type)
1544
if res:
1545
# References another struct defined in our file
1546
newentry = factory.EntryStruct(entry_type, name, tag, res.group("name"))
1547
else:
1548
raise RpcGenError('Bad type: "%s" in "%s"' % (entry_type, entry))
1549
1550
structs = []
1551
1552
if optional:
1553
newentry.MakeOptional()
1554
if array:
1555
newentry.MakeArray()
1556
1557
newentry.SetStruct(newstruct)
1558
newentry.SetLineCount(LINE_COUNT)
1559
newentry.Verify()
1560
1561
if array:
1562
# We need to encapsulate this entry into a struct
1563
newentry = factory.EntryArray(newentry)
1564
newentry.SetStruct(newstruct)
1565
newentry.SetLineCount(LINE_COUNT)
1566
newentry.MakeArray()
1567
1568
newstruct.AddEntry(newentry)
1569
1570
return structs
1571
1572
1573
def ProcessStruct(factory, data):
1574
tokens = data.split(" ")
1575
1576
# First three tokens are: 'struct' 'name' '{'
1577
newstruct = factory.Struct(tokens[1])
1578
1579
inside = " ".join(tokens[3:-1])
1580
1581
tokens = inside.split(";")
1582
1583
structs = []
1584
1585
for entry in tokens:
1586
entry = NormalizeLine(entry)
1587
if not entry:
1588
continue
1589
1590
# It's possible that new structs get defined in here
1591
structs.extend(ProcessOneEntry(factory, newstruct, entry))
1592
1593
structs.append(newstruct)
1594
return structs
1595
1596
1597
C_COMMENT_START = "/*"
1598
C_COMMENT_END = "*/"
1599
1600
C_COMMENT_START_RE = re.compile(re.escape(C_COMMENT_START))
1601
C_COMMENT_END_RE = re.compile(re.escape(C_COMMENT_END))
1602
1603
C_COMMENT_START_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_START)))
1604
C_COMMENT_END_SUB_RE = re.compile(r"%s.*$" % (re.escape(C_COMMENT_END)))
1605
1606
C_MULTILINE_COMMENT_SUB_RE = re.compile(
1607
r"%s.*?%s" % (re.escape(C_COMMENT_START), re.escape(C_COMMENT_END))
1608
)
1609
CPP_CONDITIONAL_BLOCK_RE = re.compile(r"#(if( |def)|endif)")
1610
INCLUDE_RE = re.compile(r'#include (".+"|<.+>)')
1611
1612
1613
def GetNextStruct(filep):
1614
global CPP_DIRECT
1615
global LINE_COUNT
1616
1617
got_struct = False
1618
have_c_comment = False
1619
1620
data = ""
1621
1622
while True:
1623
line = filep.readline()
1624
if not line:
1625
break
1626
1627
LINE_COUNT += 1
1628
line = line[:-1]
1629
1630
if not have_c_comment and C_COMMENT_START_RE.search(line):
1631
if C_MULTILINE_COMMENT_SUB_RE.search(line):
1632
line = C_MULTILINE_COMMENT_SUB_RE.sub("", line)
1633
else:
1634
line = C_COMMENT_START_SUB_RE.sub("", line)
1635
have_c_comment = True
1636
1637
if have_c_comment:
1638
if not C_COMMENT_END_RE.search(line):
1639
continue
1640
have_c_comment = False
1641
line = C_COMMENT_END_SUB_RE.sub("", line)
1642
1643
line = NormalizeLine(line)
1644
1645
if not line:
1646
continue
1647
1648
if not got_struct:
1649
if INCLUDE_RE.match(line):
1650
CPP_DIRECT.append(line)
1651
elif CPP_CONDITIONAL_BLOCK_RE.match(line):
1652
CPP_DIRECT.append(line)
1653
elif PREPROCESSOR_DEF_RE.match(line):
1654
HEADER_DIRECT.append(line)
1655
elif not STRUCT_DEF_RE.match(line):
1656
raise RpcGenError("Missing struct on line %d: %s" % (LINE_COUNT, line))
1657
else:
1658
got_struct = True
1659
data += line
1660
continue
1661
1662
# We are inside the struct
1663
tokens = line.split("}")
1664
if len(tokens) == 1:
1665
data += " " + line
1666
continue
1667
1668
if tokens[1]:
1669
raise RpcGenError("Trailing garbage after struct on line %d" % LINE_COUNT)
1670
1671
# We found the end of the struct
1672
data += " %s}" % tokens[0]
1673
break
1674
1675
# Remove any comments, that might be in there
1676
data = re.sub(r"/\*.*\*/", "", data)
1677
1678
return data
1679
1680
1681
def Parse(factory, filep):
1682
"""
1683
Parses the input file and returns C code and corresponding header file.
1684
"""
1685
1686
entities = []
1687
1688
while 1:
1689
# Just gets the whole struct nicely formatted
1690
data = GetNextStruct(filep)
1691
1692
if not data:
1693
break
1694
1695
entities.extend(ProcessStruct(factory, data))
1696
1697
return entities
1698
1699
1700
class CCodeGenerator(object):
1701
def __init__(self):
1702
pass
1703
1704
@staticmethod
1705
def GuardName(name):
1706
# Use the complete provided path to the input file, with all
1707
# non-identifier characters replaced with underscores, to
1708
# reduce the chance of a collision between guard macros.
1709
return "EVENT_RPCOUT_%s_" % (NONIDENT_RE.sub("_", name).upper())
1710
1711
def HeaderPreamble(self, name):
1712
guard = self.GuardName(name)
1713
pre = """
1714
/*
1715
* Automatically generated from %s
1716
*/
1717
1718
#ifndef %s
1719
#define %s
1720
1721
""" % (
1722
name,
1723
guard,
1724
guard,
1725
)
1726
1727
if HEADER_DIRECT:
1728
for statement in HEADER_DIRECT:
1729
pre += "%s\n" % statement
1730
pre += "\n"
1731
1732
pre += """
1733
#include <event2/util.h> /* for ev_uint*_t */
1734
#include <event2/rpc.h>
1735
"""
1736
1737
return pre
1738
1739
def HeaderPostamble(self, name):
1740
guard = self.GuardName(name)
1741
return "#endif /* %s */" % (guard)
1742
1743
@staticmethod
1744
def BodyPreamble(name, header_file):
1745
global _NAME
1746
global _VERSION
1747
1748
slash = header_file.rfind("/")
1749
if slash != -1:
1750
header_file = header_file[slash + 1 :]
1751
1752
pre = """
1753
/*
1754
* Automatically generated from %(name)s
1755
* by %(script_name)s/%(script_version)s. DO NOT EDIT THIS FILE.
1756
*/
1757
1758
#include <stdlib.h>
1759
#include <string.h>
1760
#include <assert.h>
1761
#include <event2/event-config.h>
1762
#include <event2/event.h>
1763
#include <event2/buffer.h>
1764
#include <event2/tag.h>
1765
1766
#if defined(EVENT__HAVE___func__)
1767
# ifndef __func__
1768
# define __func__ __func__
1769
# endif
1770
#elif defined(EVENT__HAVE___FUNCTION__)
1771
# define __func__ __FUNCTION__
1772
#else
1773
# define __func__ __FILE__
1774
#endif
1775
1776
""" % {
1777
"name": name,
1778
"script_name": _NAME,
1779
"script_version": _VERSION,
1780
}
1781
1782
for statement in CPP_DIRECT:
1783
pre += "%s\n" % statement
1784
1785
pre += '\n#include "%s"\n\n' % header_file
1786
1787
pre += "void event_warn(const char *fmt, ...);\n"
1788
pre += "void event_warnx(const char *fmt, ...);\n\n"
1789
1790
return pre
1791
1792
@staticmethod
1793
def HeaderFilename(filename):
1794
return ".".join(filename.split(".")[:-1]) + ".h"
1795
1796
@staticmethod
1797
def CodeFilename(filename):
1798
return ".".join(filename.split(".")[:-1]) + ".gen.c"
1799
1800
@staticmethod
1801
def Struct(name):
1802
return StructCCode(name)
1803
1804
@staticmethod
1805
def EntryBytes(entry_type, name, tag, fixed_length):
1806
return EntryBytes(entry_type, name, tag, fixed_length)
1807
1808
@staticmethod
1809
def EntryVarBytes(entry_type, name, tag):
1810
return EntryVarBytes(entry_type, name, tag)
1811
1812
@staticmethod
1813
def EntryInt(entry_type, name, tag, bits=32):
1814
return EntryInt(entry_type, name, tag, bits)
1815
1816
@staticmethod
1817
def EntryString(entry_type, name, tag):
1818
return EntryString(entry_type, name, tag)
1819
1820
@staticmethod
1821
def EntryStruct(entry_type, name, tag, struct_name):
1822
return EntryStruct(entry_type, name, tag, struct_name)
1823
1824
@staticmethod
1825
def EntryArray(entry):
1826
return EntryArray(entry)
1827
1828
1829
class CommandLine(object):
1830
def __init__(self, argv=None):
1831
"""Initialize a command-line to launch event_rpcgen, as if
1832
from a command-line with CommandLine(sys.argv). If you're
1833
calling this directly, remember to provide a dummy value
1834
for sys.argv[0]
1835
"""
1836
global QUIETLY
1837
1838
self.filename = None
1839
self.header_file = None
1840
self.impl_file = None
1841
self.factory = CCodeGenerator()
1842
1843
parser = argparse.ArgumentParser(
1844
usage="%(prog)s [options] rpc-file [[h-file] c-file]"
1845
)
1846
parser.add_argument("--quiet", action="store_true", default=False)
1847
parser.add_argument("rpc_file", type=argparse.FileType("r"))
1848
1849
args, extra_args = parser.parse_known_args(args=argv)
1850
1851
QUIETLY = args.quiet
1852
1853
if extra_args:
1854
if len(extra_args) == 1:
1855
self.impl_file = extra_args[0].replace("\\", "/")
1856
elif len(extra_args) == 2:
1857
self.header_file = extra_args[0].replace("\\", "/")
1858
self.impl_file = extra_args[1].replace("\\", "/")
1859
else:
1860
parser.error("Spurious arguments provided")
1861
1862
self.rpc_file = args.rpc_file
1863
1864
if not self.impl_file:
1865
self.impl_file = self.factory.CodeFilename(self.rpc_file.name)
1866
1867
if not self.header_file:
1868
self.header_file = self.factory.HeaderFilename(self.impl_file)
1869
1870
if not self.impl_file.endswith(".c"):
1871
parser.error("can only generate C implementation files")
1872
if not self.header_file.endswith(".h"):
1873
parser.error("can only generate C header files")
1874
1875
def run(self):
1876
filename = self.rpc_file.name
1877
header_file = self.header_file
1878
impl_file = self.impl_file
1879
factory = self.factory
1880
1881
declare('Reading "%s"' % filename)
1882
1883
with self.rpc_file:
1884
entities = Parse(factory, self.rpc_file)
1885
1886
declare('... creating "%s"' % header_file)
1887
with open(header_file, "w") as header_fp:
1888
header_fp.write(factory.HeaderPreamble(filename))
1889
1890
# Create forward declarations: allows other structs to reference
1891
# each other
1892
for entry in entities:
1893
entry.PrintForwardDeclaration(header_fp)
1894
header_fp.write("\n")
1895
1896
for entry in entities:
1897
entry.PrintTags(header_fp)
1898
entry.PrintDeclaration(header_fp)
1899
header_fp.write(factory.HeaderPostamble(filename))
1900
1901
declare('... creating "%s"' % impl_file)
1902
with open(impl_file, "w") as impl_fp:
1903
impl_fp.write(factory.BodyPreamble(filename, header_file))
1904
for entry in entities:
1905
entry.PrintCode(impl_fp)
1906
1907
1908
def main(argv=None):
1909
try:
1910
CommandLine(argv=argv).run()
1911
return 0
1912
except RpcGenError as e:
1913
sys.stderr.write(e)
1914
except EnvironmentError as e:
1915
if e.filename and e.strerror:
1916
sys.stderr.write("%s: %s" % (e.filename, e.strerror))
1917
elif e.strerror:
1918
sys.stderr.write(e.strerror)
1919
else:
1920
raise
1921
return 1
1922
1923
1924
if __name__ == "__main__":
1925
sys.exit(main(argv=sys.argv[1:]))
1926
1927