1#!/usr/bin/env python
2#
3# Copyright (c) 2005 Niels Provos <provos@citi.umich.edu>
4# All rights reserved.
5#
6# Generates marshaling code based on libevent.
7
8import sys
9import re
10
11#
12_NAME = "event_rpcgen.py"
13_VERSION = "0.1"
14_STRUCT_RE = '[a-z][a-z_0-9]*'
15
16# Globals
17line_count = 0
18
19white = re.compile(r'^\s+')
20cppcomment = re.compile(r'\/\/.*$')
21headerdirect = []
22cppdirect = []
23
24# Holds everything that makes a struct
25class Struct:
26    def __init__(self, name):
27        self._name = name
28        self._entries = []
29        self._tags = {}
30        print >>sys.stderr, '  Created struct: %s' % name
31
32    def AddEntry(self, entry):
33        if self._tags.has_key(entry.Tag()):
34            print >>sys.stderr, ( 'Entry "%s" duplicates tag number '
35                                  '%d from "%s" around line %d' ) % (
36                entry.Name(), entry.Tag(),
37                self._tags[entry.Tag()], line_count)
38            sys.exit(1)
39        self._entries.append(entry)
40        self._tags[entry.Tag()] = entry.Name()
41        print >>sys.stderr, '    Added entry: %s' % entry.Name()
42
43    def Name(self):
44        return self._name
45
46    def EntryTagName(self, entry):
47        """Creates the name inside an enumeration for distinguishing data
48        types."""
49        name = "%s_%s" % (self._name, entry.Name())
50        return name.upper()
51
52    def PrintIdented(self, file, ident, code):
53        """Takes an array, add indentation to each entry and prints it."""
54        for entry in code:
55            print >>file, '%s%s' % (ident, entry)
56
57    def PrintTags(self, file):
58        """Prints the tag definitions for a structure."""
59        print >>file, '/* Tag definition for %s */' % self._name
60        print >>file, 'enum %s_ {' % self._name.lower()
61        for entry in self._entries:
62            print >>file, '  %s=%d,' % (self.EntryTagName(entry),
63                                        entry.Tag())
64        print >>file, '  %s_MAX_TAGS' % (self._name.upper())
65        print >>file, '};\n'
66
67    def PrintForwardDeclaration(self, file):
68        print >>file, 'struct %s;' % self._name
69
70    def PrintDeclaration(self, file):
71        print >>file, '/* Structure declaration for %s */' % self._name
72        print >>file, 'struct %s_access_ {' % self._name
73        for entry in self._entries:
74            dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
75            dcl.extend(
76                entry.GetDeclaration('(*%s_get)' % entry.Name()))
77            if entry.Array():
78                dcl.extend(
79                    entry.AddDeclaration('(*%s_add)' % entry.Name()))
80            self.PrintIdented(file, '  ', dcl)
81        print >>file, '};\n'
82
83        print >>file, 'struct %s {' % self._name
84        print >>file, '  struct %s_access_ *base;\n' % self._name
85        for entry in self._entries:
86            dcl = entry.Declaration()
87            self.PrintIdented(file, '  ', dcl)
88        print >>file, ''
89        for entry in self._entries:
90            print >>file, '  ev_uint8_t %s_set;' % entry.Name()
91        print >>file, '};\n'
92
93        print >>file, \
94"""struct %(name)s *%(name)s_new(void);
95void %(name)s_free(struct %(name)s *);
96void %(name)s_clear(struct %(name)s *);
97void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
98int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
99int %(name)s_complete(struct %(name)s *);
100void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
101    const struct %(name)s *);
102int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
103    struct %(name)s *);""" % { 'name' : self._name }
104
105
106        # Write a setting function of every variable
107        for entry in self._entries:
108            self.PrintIdented(file, '', entry.AssignDeclaration(
109                entry.AssignFuncName()))
110            self.PrintIdented(file, '', entry.GetDeclaration(
111                entry.GetFuncName()))
112            if entry.Array():
113                self.PrintIdented(file, '', entry.AddDeclaration(
114                    entry.AddFuncName()))
115
116        print >>file, '/* --- %s done --- */\n' % self._name
117
118    def PrintCode(self, file):
119        print >>file, ('/*\n'
120                       ' * Implementation of %s\n'
121                       ' */\n') % self._name
122
123        print >>file, \
124              'static struct %(name)s_access_ __%(name)s_base = {' % \
125              { 'name' : self._name }
126        for entry in self._entries:
127            self.PrintIdented(file, '  ', entry.CodeBase())
128        print >>file, '};\n'
129
130        # Creation
131        print >>file, (
132            'struct %(name)s *\n'
133            '%(name)s_new(void)\n'
134            '{\n'
135            '  struct %(name)s *tmp;\n'
136            '  if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n'
137            '    event_warn("%%s: malloc", __func__);\n'
138            '    return (NULL);\n'
139            '  }\n'
140            '  tmp->base = &__%(name)s_base;\n') % { 'name' : self._name }
141
142        for entry in self._entries:
143            self.PrintIdented(file, '  ', entry.CodeNew('tmp'))
144            print >>file, '  tmp->%s_set = 0;\n' % entry.Name()
145
146        print >>file, (
147            '  return (tmp);\n'
148            '}\n')
149
150        # Adding
151        for entry in self._entries:
152            if entry.Array():
153                self.PrintIdented(file, '', entry.CodeAdd())
154            print >>file, ''
155
156        # Assigning
157        for entry in self._entries:
158            self.PrintIdented(file, '', entry.CodeAssign())
159            print >>file, ''
160
161        # Getting
162        for entry in self._entries:
163            self.PrintIdented(file, '', entry.CodeGet())
164            print >>file, ''
165
166        # Clearing
167        print >>file, ( 'void\n'
168                        '%(name)s_clear(struct %(name)s *tmp)\n'
169                        '{'
170                        ) % { 'name' : self._name }
171        for entry in self._entries:
172            self.PrintIdented(file, '  ', entry.CodeClear('tmp'))
173
174        print >>file, '}\n'
175
176        # Freeing
177        print >>file, ( 'void\n'
178                        '%(name)s_free(struct %(name)s *tmp)\n'
179                        '{'
180                        ) % { 'name' : self._name }
181
182        for entry in self._entries:
183            self.PrintIdented(file, '  ', entry.CodeFree('tmp'))
184
185        print >>file, ('  free(tmp);\n'
186                       '}\n')
187
188        # Marshaling
189        print >>file, ('void\n'
190                       '%(name)s_marshal(struct evbuffer *evbuf, '
191                       'const struct %(name)s *tmp)'
192                       '{') % { 'name' : self._name }
193        for entry in self._entries:
194            indent = '  '
195            # Optional entries do not have to be set
196            if entry.Optional():
197                indent += '  '
198                print >>file, '  if (tmp->%s_set) {' % entry.Name()
199            self.PrintIdented(
200                file, indent,
201                entry.CodeMarshal('evbuf', self.EntryTagName(entry), 'tmp'))
202            if entry.Optional():
203                print >>file, '  }'
204
205        print >>file, '}\n'
206
207        # Unmarshaling
208        print >>file, ('int\n'
209                       '%(name)s_unmarshal(struct %(name)s *tmp, '
210                       ' struct evbuffer *evbuf)\n'
211                       '{\n'
212                       '  ev_uint32_t tag;\n'
213                       '  while (EVBUFFER_LENGTH(evbuf) > 0) {\n'
214                       '    if (evtag_peek(evbuf, &tag) == -1)\n'
215                       '      return (-1);\n'
216                       '    switch (tag) {\n'
217                       ) % { 'name' : self._name }
218        for entry in self._entries:
219            print >>file, '      case %s:\n' % self.EntryTagName(entry)
220            if not entry.Array():
221                print >>file, (
222                    '        if (tmp->%s_set)\n'
223                    '          return (-1);'
224                    ) % (entry.Name())
225
226            self.PrintIdented(
227                file, '        ',
228                entry.CodeUnmarshal('evbuf',
229                                    self.EntryTagName(entry), 'tmp'))
230
231            print >>file, ( '        tmp->%s_set = 1;\n' % entry.Name() +
232                            '        break;\n' )
233        print >>file, ( '      default:\n'
234                        '        return -1;\n'
235                        '    }\n'
236                        '  }\n' )
237        # Check if it was decoded completely
238        print >>file, ( '  if (%(name)s_complete(tmp) == -1)\n'
239                        '    return (-1);'
240                        ) % { 'name' : self._name }
241
242        # Successfully decoded
243        print >>file, ( '  return (0);\n'
244                        '}\n')
245
246        # Checking if a structure has all the required data
247        print >>file, (
248            'int\n'
249            '%(name)s_complete(struct %(name)s *msg)\n'
250            '{' ) % { 'name' : self._name }
251        for entry in self._entries:
252            self.PrintIdented(
253                file, '  ',
254                entry.CodeComplete('msg'))
255        print >>file, (
256            '  return (0);\n'
257            '}\n' )
258
259        # Complete message unmarshaling
260        print >>file, (
261            'int\n'
262            'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
263            'ev_uint32_t need_tag, struct %(name)s *msg)\n'
264            '{\n'
265            '  ev_uint32_t tag;\n'
266            '  int res = -1;\n'
267            '\n'
268            '  struct evbuffer *tmp = evbuffer_new();\n'
269            '\n'
270            '  if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
271            ' || tag != need_tag)\n'
272            '    goto error;\n'
273            '\n'
274            '  if (%(name)s_unmarshal(msg, tmp) == -1)\n'
275            '    goto error;\n'
276            '\n'
277            '  res = 0;\n'
278            '\n'
279            ' error:\n'
280            '  evbuffer_free(tmp);\n'
281            '  return (res);\n'
282            '}\n' ) % { 'name' : self._name }
283
284        # Complete message marshaling
285        print >>file, (
286            'void\n'
287            'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
288            'const struct %(name)s *msg)\n'
289            '{\n'
290            '  struct evbuffer *_buf = evbuffer_new();\n'
291            '  assert(_buf != NULL);\n'
292            '  evbuffer_drain(_buf, -1);\n'
293            '  %(name)s_marshal(_buf, msg);\n'
294            '  evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), '
295            'EVBUFFER_LENGTH(_buf));\n'
296            '  evbuffer_free(_buf);\n'
297            '}\n' ) % { 'name' : self._name }
298
299class Entry:
300    def __init__(self, type, name, tag):
301        self._type = type
302        self._name = name
303        self._tag = int(tag)
304        self._ctype = type
305        self._optional = 0
306        self._can_be_array = 0
307        self._array = 0
308        self._line_count = -1
309        self._struct = None
310        self._refname = None
311
312    def GetTranslation(self):
313        return { "parent_name" : self._struct.Name(),
314                 "name" : self._name,
315                 "ctype" : self._ctype,
316                 "refname" : self._refname
317                 }
318
319    def SetStruct(self, struct):
320        self._struct = struct
321
322    def LineCount(self):
323        assert self._line_count != -1
324        return self._line_count
325
326    def SetLineCount(self, number):
327        self._line_count = number
328
329    def Array(self):
330        return self._array
331
332    def Optional(self):
333        return self._optional
334
335    def Tag(self):
336        return self._tag
337
338    def Name(self):
339        return self._name
340
341    def Type(self):
342        return self._type
343
344    def MakeArray(self, yes=1):
345        self._array = yes
346
347    def MakeOptional(self):
348        self._optional = 1
349
350    def GetFuncName(self):
351        return '%s_%s_get' % (self._struct.Name(), self._name)
352
353    def GetDeclaration(self, funcname):
354        code = [ 'int %s(struct %s *, %s *);' % (
355            funcname, self._struct.Name(), self._ctype ) ]
356        return code
357
358    def CodeGet(self):
359        code = (
360            'int',
361            '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, '
362            '%(ctype)s *value)',
363            '{',
364            '  if (msg->%(name)s_set != 1)',
365            '    return (-1);',
366            '  *value = msg->%(name)s_data;',
367            '  return (0);',
368            '}' )
369        code = '\n'.join(code)
370        code = code % self.GetTranslation()
371        return code.split('\n')
372
373    def AssignFuncName(self):
374        return '%s_%s_assign' % (self._struct.Name(), self._name)
375
376    def AddFuncName(self):
377        return '%s_%s_add' % (self._struct.Name(), self._name)
378
379    def AssignDeclaration(self, funcname):
380        code = [ 'int %s(struct %s *, const %s);' % (
381            funcname, self._struct.Name(), self._ctype ) ]
382        return code
383
384    def CodeAssign(self):
385        code = [ 'int',
386                 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,'
387                 ' const %(ctype)s value)',
388                 '{',
389                 '  msg->%(name)s_set = 1;',
390                 '  msg->%(name)s_data = value;',
391                 '  return (0);',
392                 '}' ]
393        code = '\n'.join(code)
394        code = code % self.GetTranslation()
395        return code.split('\n')
396
397    def CodeClear(self, structname):
398        code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
399
400        return code
401
402    def CodeComplete(self, structname):
403        if self.Optional():
404            return []
405
406        code = [ 'if (!%s->%s_set)' % (structname, self.Name()),
407                 '  return (-1);' ]
408
409        return code
410
411    def CodeFree(self, name):
412        return []
413
414    def CodeBase(self):
415        code = [
416            '%(parent_name)s_%(name)s_assign,',
417            '%(parent_name)s_%(name)s_get,'
418            ]
419        if self.Array():
420            code.append('%(parent_name)s_%(name)s_add,')
421
422        code = '\n'.join(code)
423        code = code % self.GetTranslation()
424        return code.split('\n')
425
426    def Verify(self):
427        if self.Array() and not self._can_be_array:
428            print >>sys.stderr, (
429                'Entry "%s" cannot be created as an array '
430                'around line %d' ) % (self._name, self.LineCount())
431            sys.exit(1)
432        if not self._struct:
433            print >>sys.stderr, (
434                'Entry "%s" does not know which struct it belongs to '
435                'around line %d' ) % (self._name, self.LineCount())
436            sys.exit(1)
437        if self._optional and self._array:
438            print >>sys.stderr,  ( 'Entry "%s" has illegal combination of '
439                                   'optional and array around line %d' ) % (
440                self._name, self.LineCount() )
441            sys.exit(1)
442
443class EntryBytes(Entry):
444    def __init__(self, type, name, tag, length):
445        # Init base class
446        Entry.__init__(self, type, name, tag)
447
448        self._length = length
449        self._ctype = 'ev_uint8_t'
450
451    def GetDeclaration(self, funcname):
452        code = [ 'int %s(struct %s *, %s **);' % (
453            funcname, self._struct.Name(), self._ctype ) ]
454        return code
455
456    def AssignDeclaration(self, funcname):
457        code = [ 'int %s(struct %s *, const %s *);' % (
458            funcname, self._struct.Name(), self._ctype ) ]
459        return code
460
461    def Declaration(self):
462        dcl  = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)]
463
464        return dcl
465
466    def CodeGet(self):
467        name = self._name
468        code = [ 'int',
469                 '%s_%s_get(struct %s *msg, %s **value)' % (
470            self._struct.Name(), name,
471            self._struct.Name(), self._ctype),
472                 '{',
473                 '  if (msg->%s_set != 1)' % name,
474                 '    return (-1);',
475                 '  *value = msg->%s_data;' % name,
476                 '  return (0);',
477                 '}' ]
478        return code
479
480    def CodeAssign(self):
481        name = self._name
482        code = [ 'int',
483                 '%s_%s_assign(struct %s *msg, const %s *value)' % (
484            self._struct.Name(), name,
485            self._struct.Name(), self._ctype),
486                 '{',
487                 '  msg->%s_set = 1;' % name,
488                 '  memcpy(msg->%s_data, value, %s);' % (
489            name, self._length),
490                 '  return (0);',
491                 '}' ]
492        return code
493
494    def CodeUnmarshal(self, buf, tag_name, var_name):
495        code = [  'if (evtag_unmarshal_fixed(%s, %s, ' % (buf, tag_name) +
496                  '%s->%s_data, ' % (var_name, self._name) +
497                  'sizeof(%s->%s_data)) == -1) {' % (
498            var_name, self._name),
499                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
500            self._name ),
501                  '  return (-1);',
502                  '}'
503                  ]
504        return code
505
506    def CodeMarshal(self, buf, tag_name, var_name):
507        code = ['evtag_marshal(%s, %s, %s->%s_data, sizeof(%s->%s_data));' % (
508            buf, tag_name, var_name, self._name, var_name, self._name )]
509        return code
510
511    def CodeClear(self, structname):
512        code = [ '%s->%s_set = 0;' % (structname, self.Name()),
513                 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
514            structname, self._name, structname, self._name)]
515
516        return code
517
518    def CodeNew(self, name):
519        code  = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
520            name, self._name, name, self._name)]
521        return code
522
523    def Verify(self):
524        if not self._length:
525            print >>sys.stderr, 'Entry "%s" needs a length around line %d' % (
526                self._name, self.LineCount() )
527            sys.exit(1)
528
529        Entry.Verify(self)
530
531class EntryInt(Entry):
532    def __init__(self, type, name, tag):
533        # Init base class
534        Entry.__init__(self, type, name, tag)
535
536        self._ctype = 'ev_uint32_t'
537
538    def CodeUnmarshal(self, buf, tag_name, var_name):
539        code = ['if (evtag_unmarshal_int(%s, %s, &%s->%s_data) == -1) {' % (
540            buf, tag_name, var_name, self._name),
541                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
542            self._name ),
543                '  return (-1);',
544                '}' ]
545        return code
546
547    def CodeMarshal(self, buf, tag_name, var_name):
548        code = ['evtag_marshal_int(%s, %s, %s->%s_data);' % (
549            buf, tag_name, var_name, self._name)]
550        return code
551
552    def Declaration(self):
553        dcl  = ['ev_uint32_t %s_data;' % self._name]
554
555        return dcl
556
557    def CodeNew(self, name):
558        code = ['%s->%s_data = 0;' % (name, self._name)]
559        return code
560
561class EntryString(Entry):
562    def __init__(self, type, name, tag):
563        # Init base class
564        Entry.__init__(self, type, name, tag)
565
566        self._ctype = 'char *'
567
568    def CodeAssign(self):
569        name = self._name
570        code = """int
571%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
572    const %(ctype)s value)
573{
574  if (msg->%(name)s_data != NULL)
575    free(msg->%(name)s_data);
576  if ((msg->%(name)s_data = strdup(value)) == NULL)
577    return (-1);
578  msg->%(name)s_set = 1;
579  return (0);
580}""" % self.GetTranslation()
581
582        return code.split('\n')
583
584    def CodeUnmarshal(self, buf, tag_name, var_name):
585        code = ['if (evtag_unmarshal_string(%s, %s, &%s->%s_data) == -1) {' % (
586            buf, tag_name, var_name, self._name),
587                '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
588            self._name ),
589                '  return (-1);',
590                '}'
591                ]
592        return code
593
594    def CodeMarshal(self, buf, tag_name, var_name):
595        code = ['evtag_marshal_string(%s, %s, %s->%s_data);' % (
596            buf, tag_name, var_name, self._name)]
597        return code
598
599    def CodeClear(self, structname):
600        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
601                 '  free (%s->%s_data);' % (structname, self.Name()),
602                 '  %s->%s_data = NULL;' % (structname, self.Name()),
603                 '  %s->%s_set = 0;' % (structname, self.Name()),
604                 '}'
605                 ]
606
607        return code
608
609    def CodeNew(self, name):
610        code  = ['%s->%s_data = NULL;' % (name, self._name)]
611        return code
612
613    def CodeFree(self, name):
614        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
615                 '    free (%s->%s_data); ' % (name, self._name)]
616
617        return code
618
619    def Declaration(self):
620        dcl  = ['char *%s_data;' % self._name]
621
622        return dcl
623
624class EntryStruct(Entry):
625    def __init__(self, type, name, tag, refname):
626        # Init base class
627        Entry.__init__(self, type, name, tag)
628
629        self._can_be_array = 1
630        self._refname = refname
631        self._ctype = 'struct %s*' % refname
632
633    def CodeGet(self):
634        name = self._name
635        code = [ 'int',
636                 '%s_%s_get(struct %s *msg, %s *value)' % (
637            self._struct.Name(), name,
638            self._struct.Name(), self._ctype),
639                 '{',
640                 '  if (msg->%s_set != 1) {' % name,
641                 '    msg->%s_data = %s_new();' % (name, self._refname),
642                 '    if (msg->%s_data == NULL)' % name,
643                 '      return (-1);',
644                 '    msg->%s_set = 1;' % name,
645                 '  }',
646                 '  *value = msg->%s_data;' % name,
647                 '  return (0);',
648                 '}' ]
649        return code
650
651    def CodeAssign(self):
652        name = self._name
653        code = """int
654%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
655    const %(ctype)s value)
656{
657   struct evbuffer *tmp = NULL;
658   if (msg->%(name)s_set) {
659     %(refname)s_clear(msg->%(name)s_data);
660     msg->%(name)s_set = 0;
661   } else {
662     msg->%(name)s_data = %(refname)s_new();
663     if (msg->%(name)s_data == NULL) {
664       event_warn("%%s: %(refname)s_new()", __func__);
665       goto error;
666     }
667   }
668   if ((tmp = evbuffer_new()) == NULL) {
669     event_warn("%%s: evbuffer_new()", __func__);
670     goto error;
671   }
672   %(refname)s_marshal(tmp, value);
673   if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
674     event_warnx("%%s: %(refname)s_unmarshal", __func__);
675     goto error;
676   }
677   msg->%(name)s_set = 1;
678   evbuffer_free(tmp);
679   return (0);
680 error:
681   if (tmp != NULL)
682     evbuffer_free(tmp);
683   if (msg->%(name)s_data != NULL) {
684     %(refname)s_free(msg->%(name)s_data);
685     msg->%(name)s_data = NULL;
686   }
687   return (-1);
688}""" % self.GetTranslation()
689        return code.split('\n')
690
691    def CodeComplete(self, structname):
692        if self.Optional():
693            code = [ 'if (%s->%s_set && %s_complete(%s->%s_data) == -1)' % (
694                structname, self.Name(),
695                self._refname, structname, self.Name()),
696                     '  return (-1);' ]
697        else:
698            code = [ 'if (%s_complete(%s->%s_data) == -1)' % (
699                self._refname, structname, self.Name()),
700                     '  return (-1);' ]
701
702        return code
703
704    def CodeUnmarshal(self, buf, tag_name, var_name):
705        code = ['%s->%s_data = %s_new();' % (
706            var_name, self._name, self._refname),
707                'if (%s->%s_data == NULL)' % (var_name, self._name),
708                '  return (-1);',
709                'if (evtag_unmarshal_%s(%s, %s, %s->%s_data) == -1) {' % (
710            self._refname, buf, tag_name, var_name, self._name),
711                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
712            self._name ),
713                '  return (-1);',
714                '}'
715                ]
716        return code
717
718    def CodeMarshal(self, buf, tag_name, var_name):
719        code = ['evtag_marshal_%s(%s, %s, %s->%s_data);' % (
720            self._refname, buf, tag_name, var_name, self._name)]
721        return code
722
723    def CodeClear(self, structname):
724        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
725                 '  %s_free(%s->%s_data);' % (
726            self._refname, structname, self.Name()),
727                 '  %s->%s_data = NULL;' % (structname, self.Name()),
728                 '  %s->%s_set = 0;' % (structname, self.Name()),
729                 '}'
730                 ]
731
732        return code
733
734    def CodeNew(self, name):
735        code  = ['%s->%s_data = NULL;' % (name, self._name)]
736        return code
737
738    def CodeFree(self, name):
739        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
740                 '    %s_free(%s->%s_data); ' % (
741            self._refname, name, self._name)]
742
743        return code
744
745    def Declaration(self):
746        dcl  = ['%s %s_data;' % (self._ctype, self._name)]
747
748        return dcl
749
750class EntryVarBytes(Entry):
751    def __init__(self, type, name, tag):
752        # Init base class
753        Entry.__init__(self, type, name, tag)
754
755        self._ctype = 'ev_uint8_t *'
756
757    def GetDeclaration(self, funcname):
758        code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % (
759            funcname, self._struct.Name(), self._ctype ) ]
760        return code
761
762    def AssignDeclaration(self, funcname):
763        code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % (
764            funcname, self._struct.Name(), self._ctype ) ]
765        return code
766
767    def CodeAssign(self):
768        name = self._name
769        code = [ 'int',
770                 '%s_%s_assign(struct %s *msg, '
771                 'const %s value, ev_uint32_t len)' % (
772            self._struct.Name(), name,
773            self._struct.Name(), self._ctype),
774                 '{',
775                 '  if (msg->%s_data != NULL)' % name,
776                 '    free (msg->%s_data);' % name,
777                 '  msg->%s_data = malloc(len);' % name,
778                 '  if (msg->%s_data == NULL)' % name,
779                 '    return (-1);',
780                 '  msg->%s_set = 1;' % name,
781                 '  msg->%s_length = len;' % name,
782                 '  memcpy(msg->%s_data, value, len);' % name,
783                 '  return (0);',
784                 '}' ]
785        return code
786
787    def CodeGet(self):
788        name = self._name
789        code = [ 'int',
790                 '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % (
791            self._struct.Name(), name,
792            self._struct.Name(), self._ctype),
793                 '{',
794                 '  if (msg->%s_set != 1)' % name,
795                 '    return (-1);',
796                 '  *value = msg->%s_data;' % name,
797                 '  *plen = msg->%s_length;' % name,
798                 '  return (0);',
799                 '}' ]
800        return code
801
802    def CodeUnmarshal(self, buf, tag_name, var_name):
803        code = ['if (evtag_payload_length(%s, &%s->%s_length) == -1)' % (
804            buf, var_name, self._name),
805                '  return (-1);',
806                # We do not want DoS opportunities
807                'if (%s->%s_length > EVBUFFER_LENGTH(%s))' % (
808            var_name, self._name, buf),
809                '  return (-1);',
810                'if ((%s->%s_data = malloc(%s->%s_length)) == NULL)' % (
811            var_name, self._name, var_name, self._name),
812                '  return (-1);',
813                'if (evtag_unmarshal_fixed(%s, %s, %s->%s_data, '
814                '%s->%s_length) == -1) {' % (
815            buf, tag_name, var_name, self._name, var_name, self._name),
816                '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
817            self._name ),
818                '  return (-1);',
819                '}'
820                ]
821        return code
822
823    def CodeMarshal(self, buf, tag_name, var_name):
824        code = ['evtag_marshal(%s, %s, %s->%s_data, %s->%s_length);' % (
825            buf, tag_name, var_name, self._name, var_name, self._name)]
826        return code
827
828    def CodeClear(self, structname):
829        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
830                 '  free (%s->%s_data);' % (structname, self.Name()),
831                 '  %s->%s_data = NULL;' % (structname, self.Name()),
832                 '  %s->%s_length = 0;' % (structname, self.Name()),
833                 '  %s->%s_set = 0;' % (structname, self.Name()),
834                 '}'
835                 ]
836
837        return code
838
839    def CodeNew(self, name):
840        code  = ['%s->%s_data = NULL;' % (name, self._name),
841                 '%s->%s_length = 0;' % (name, self._name) ]
842        return code
843
844    def CodeFree(self, name):
845        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
846                 '    free (%s->%s_data); ' % (name, self._name)]
847
848        return code
849
850    def Declaration(self):
851        dcl  = ['ev_uint8_t *%s_data;' % self._name,
852                'ev_uint32_t %s_length;' % self._name]
853
854        return dcl
855
856class EntryArray(Entry):
857    def __init__(self, entry):
858        # Init base class
859        Entry.__init__(self, entry._type, entry._name, entry._tag)
860
861        self._entry = entry
862        self._refname = entry._refname
863        self._ctype = 'struct %s *' % self._refname
864
865    def GetDeclaration(self, funcname):
866        """Allows direct access to elements of the array."""
867        translate = self.GetTranslation()
868        translate["funcname"] = funcname
869        code = [
870            'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' %
871            translate ]
872        return code
873
874    def AssignDeclaration(self, funcname):
875        code = [ 'int %s(struct %s *, int, const %s);' % (
876            funcname, self._struct.Name(), self._ctype ) ]
877        return code
878
879    def AddDeclaration(self, funcname):
880        code = [ '%s %s(struct %s *);' % (
881            self._ctype, funcname, self._struct.Name() ) ]
882        return code
883
884    def CodeGet(self):
885        code = """int
886%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
887    %(ctype)s *value)
888{
889  if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
890    return (-1);
891  *value = msg->%(name)s_data[offset];
892  return (0);
893}""" % self.GetTranslation()
894
895        return code.split('\n')
896
897    def CodeAssign(self):
898        code = """int
899%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,
900    const %(ctype)s value)
901{
902  struct evbuffer *tmp = NULL;
903  if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)
904    return (-1);
905  %(refname)s_clear(msg->%(name)s_data[off]);
906  if ((tmp = evbuffer_new()) == NULL) {
907    event_warn("%%s: evbuffer_new()", __func__);
908    goto error;
909  }
910  %(refname)s_marshal(tmp, value);
911  if (%(refname)s_unmarshal(msg->%(name)s_data[off], tmp) == -1) {
912    event_warnx("%%s: %(refname)s_unmarshal", __func__);
913    goto error;
914  }
915  evbuffer_free(tmp);
916  return (0);
917error:
918  if (tmp != NULL)
919    evbuffer_free(tmp);
920  %(refname)s_clear(msg->%(name)s_data[off]);
921  return (-1);
922}""" % self.GetTranslation()
923
924        return code.split('\n')
925
926    def CodeAdd(self):
927        code = \
928"""%(ctype)s
929%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg)
930{
931  if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {
932    int tobe_allocated = msg->%(name)s_num_allocated;
933    %(ctype)s* new_data = NULL;
934    tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
935    new_data = (%(ctype)s*) realloc(msg->%(name)s_data,
936        tobe_allocated * sizeof(%(ctype)s));
937    if (new_data == NULL)
938      goto error;
939    msg->%(name)s_data = new_data;
940    msg->%(name)s_num_allocated = tobe_allocated;
941  }
942  msg->%(name)s_data[msg->%(name)s_length - 1] = %(refname)s_new();
943  if (msg->%(name)s_data[msg->%(name)s_length - 1] == NULL)
944    goto error;
945  msg->%(name)s_set = 1;
946  return (msg->%(name)s_data[msg->%(name)s_length - 1]);
947error:
948  --msg->%(name)s_length;
949  return (NULL);
950}
951        """ % self.GetTranslation()
952
953        return code.split('\n')
954
955    def CodeComplete(self, structname):
956        code = []
957        translate = self.GetTranslation()
958
959        if self.Optional():
960            code.append( 'if (%(structname)s->%(name)s_set)'  % translate)
961
962        translate["structname"] = structname
963        tmp = """{
964  int i;
965  for (i = 0; i < %(structname)s->%(name)s_length; ++i) {
966    if (%(refname)s_complete(%(structname)s->%(name)s_data[i]) == -1)
967      return (-1);
968  }
969}""" % translate
970        code.extend(tmp.split('\n'))
971
972        return code
973
974    def CodeUnmarshal(self, buf, tag_name, var_name):
975        translate = self.GetTranslation()
976        translate["var_name"] = var_name
977        translate["buf"] = buf
978        translate["tag_name"] = tag_name
979        code = """if (%(parent_name)s_%(name)s_add(%(var_name)s) == NULL)
980  return (-1);
981if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag_name)s,
982  %(var_name)s->%(name)s_data[%(var_name)s->%(name)s_length - 1]) == -1) {
983  --%(var_name)s->%(name)s_length;
984  event_warnx("%%s: failed to unmarshal %(name)s", __func__);
985  return (-1);
986}""" % translate
987
988        return code.split('\n')
989
990    def CodeMarshal(self, buf, tag_name, var_name):
991        code = ['{',
992                '  int i;',
993                '  for (i = 0; i < %s->%s_length; ++i) {' % (
994            var_name, self._name),
995                '    evtag_marshal_%s(%s, %s, %s->%s_data[i]);' % (
996            self._refname, buf, tag_name, var_name, self._name),
997                '  }',
998                '}'
999                ]
1000        return code
1001
1002    def CodeClear(self, structname):
1003        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
1004                 '  int i;',
1005                 '  for (i = 0; i < %s->%s_length; ++i) {' % (
1006            structname, self.Name()),
1007                 '    %s_free(%s->%s_data[i]);' % (
1008            self._refname, structname, self.Name()),
1009                 '  }',
1010                 '  free(%s->%s_data);' % (structname, self.Name()),
1011                 '  %s->%s_data = NULL;' % (structname, self.Name()),
1012                 '  %s->%s_set = 0;' % (structname, self.Name()),
1013                 '  %s->%s_length = 0;' % (structname, self.Name()),
1014                 '  %s->%s_num_allocated = 0;' % (structname, self.Name()),
1015                 '}'
1016                 ]
1017
1018        return code
1019
1020    def CodeNew(self, name):
1021        code  = ['%s->%s_data = NULL;' % (name, self._name),
1022                 '%s->%s_length = 0;' % (name, self._name),
1023                 '%s->%s_num_allocated = 0;' % (name, self._name)]
1024        return code
1025
1026    def CodeFree(self, name):
1027        code  = ['if (%s->%s_data != NULL) {' % (name, self._name),
1028                 '  int i;',
1029                 '  for (i = 0; i < %s->%s_length; ++i) {' % (
1030            name, self._name),
1031                 '    %s_free(%s->%s_data[i]); ' % (
1032            self._refname, name, self._name),
1033                 '    %s->%s_data[i] = NULL;' % (name, self._name),
1034                 '  }',
1035                 '  free(%s->%s_data);' % (name, self._name),
1036                 '  %s->%s_data = NULL;' % (name, self._name),
1037                 '  %s->%s_length = 0;' % (name, self._name),
1038                 '  %s->%s_num_allocated = 0;' % (name, self._name),
1039                 '}'
1040                 ]
1041
1042        return code
1043
1044    def Declaration(self):
1045        dcl  = ['struct %s **%s_data;' % (self._refname, self._name),
1046                'int %s_length;' % self._name,
1047                'int %s_num_allocated;' % self._name ]
1048
1049        return dcl
1050
1051def NormalizeLine(line):
1052    global white
1053    global cppcomment
1054
1055    line = cppcomment.sub('', line)
1056    line = line.strip()
1057    line = white.sub(' ', line)
1058
1059    return line
1060
1061def ProcessOneEntry(newstruct, entry):
1062    optional = 0
1063    array = 0
1064    entry_type = ''
1065    name = ''
1066    tag = ''
1067    tag_set = None
1068    separator = ''
1069    fixed_length = ''
1070
1071    tokens = entry.split(' ')
1072    while tokens:
1073        token = tokens[0]
1074        tokens = tokens[1:]
1075
1076        if not entry_type:
1077            if not optional and token == 'optional':
1078                optional = 1
1079                continue
1080
1081            if not array and token == 'array':
1082                array = 1
1083                continue
1084
1085        if not entry_type:
1086            entry_type = token
1087            continue
1088
1089        if not name:
1090            res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
1091            if not res:
1092                print >>sys.stderr, 'Cannot parse name: \"%s\" around %d' % (
1093                    entry, line_count)
1094                sys.exit(1)
1095            name = res.group(1)
1096            fixed_length = res.group(2)
1097            if fixed_length:
1098                fixed_length = fixed_length[1:-1]
1099            continue
1100
1101        if not separator:
1102            separator = token
1103            if separator != '=':
1104                print >>sys.stderr, 'Expected "=" after name \"%s\" got %s' % (
1105                    name, token)
1106                sys.exit(1)
1107            continue
1108
1109        if not tag_set:
1110            tag_set = 1
1111            if not re.match(r'^(0x)?[0-9]+$', token):
1112                print >>sys.stderr, 'Expected tag number: \"%s\"' % entry
1113                sys.exit(1)
1114            tag = int(token, 0)
1115            continue
1116
1117        print >>sys.stderr, 'Cannot parse \"%s\"' % entry
1118        sys.exit(1)
1119
1120    if not tag_set:
1121        print >>sys.stderr, 'Need tag number: \"%s\"' % entry
1122        sys.exit(1)
1123
1124    # Create the right entry
1125    if entry_type == 'bytes':
1126        if fixed_length:
1127            newentry = EntryBytes(entry_type, name, tag, fixed_length)
1128        else:
1129            newentry = EntryVarBytes(entry_type, name, tag)
1130    elif entry_type == 'int' and not fixed_length:
1131        newentry = EntryInt(entry_type, name, tag)
1132    elif entry_type == 'string' and not fixed_length:
1133        newentry = EntryString(entry_type, name, tag)
1134    else:
1135        res = re.match(r'^struct\[(%s)\]$' % _STRUCT_RE,
1136                       entry_type, re.IGNORECASE)
1137        if res:
1138            # References another struct defined in our file
1139            newentry = EntryStruct(entry_type, name, tag, res.group(1))
1140        else:
1141            print >>sys.stderr, 'Bad type: "%s" in "%s"' % (entry_type, entry)
1142            sys.exit(1)
1143
1144    structs = []
1145
1146    if optional:
1147        newentry.MakeOptional()
1148    if array:
1149        newentry.MakeArray()
1150
1151    newentry.SetStruct(newstruct)
1152    newentry.SetLineCount(line_count)
1153    newentry.Verify()
1154
1155    if array:
1156        # We need to encapsulate this entry into a struct
1157        newname = newentry.Name()+ '_array'
1158
1159        # Now borgify the new entry.
1160        newentry = EntryArray(newentry)
1161        newentry.SetStruct(newstruct)
1162        newentry.SetLineCount(line_count)
1163        newentry.MakeArray()
1164
1165    newstruct.AddEntry(newentry)
1166
1167    return structs
1168
1169def ProcessStruct(data):
1170    tokens = data.split(' ')
1171
1172    # First three tokens are: 'struct' 'name' '{'
1173    newstruct = Struct(tokens[1])
1174
1175    inside = ' '.join(tokens[3:-1])
1176
1177    tokens = inside.split(';')
1178
1179    structs = []
1180
1181    for entry in tokens:
1182        entry = NormalizeLine(entry)
1183        if not entry:
1184            continue
1185
1186        # It's possible that new structs get defined in here
1187        structs.extend(ProcessOneEntry(newstruct, entry))
1188
1189    structs.append(newstruct)
1190    return structs
1191
1192def GetNextStruct(file):
1193    global line_count
1194    global cppdirect
1195
1196    got_struct = 0
1197
1198    processed_lines = []
1199
1200    have_c_comment = 0
1201    data = ''
1202    while 1:
1203        line = file.readline()
1204        if not line:
1205            break
1206
1207        line_count += 1
1208        line = line[:-1]
1209
1210        if not have_c_comment and re.search(r'/\*', line):
1211            if re.search(r'/\*.*\*/', line):
1212                line = re.sub(r'/\*.*\*/', '', line)
1213            else:
1214                line = re.sub(r'/\*.*$', '', line)
1215                have_c_comment = 1
1216
1217        if have_c_comment:
1218            if not re.search(r'\*/', line):
1219                continue
1220            have_c_comment = 0
1221            line = re.sub(r'^.*\*/', '', line)
1222
1223        line = NormalizeLine(line)
1224
1225        if not line:
1226            continue
1227
1228        if not got_struct:
1229            if re.match(r'#include ["<].*[>"]', line):
1230                cppdirect.append(line)
1231                continue
1232
1233            if re.match(r'^#(if( |def)|endif)', line):
1234                cppdirect.append(line)
1235                continue
1236
1237            if re.match(r'^#define', line):
1238                headerdirect.append(line)
1239                continue
1240
1241            if not re.match(r'^struct %s {$' % _STRUCT_RE,
1242                            line, re.IGNORECASE):
1243                print >>sys.stderr, 'Missing struct on line %d: %s' % (
1244                    line_count, line)
1245                sys.exit(1)
1246            else:
1247                got_struct = 1
1248                data += line
1249            continue
1250
1251        # We are inside the struct
1252        tokens = line.split('}')
1253        if len(tokens) == 1:
1254            data += ' ' + line
1255            continue
1256
1257        if len(tokens[1]):
1258            print >>sys.stderr, 'Trailing garbage after struct on line %d' % (
1259                line_count )
1260            sys.exit(1)
1261
1262        # We found the end of the struct
1263        data += ' %s}' % tokens[0]
1264        break
1265
1266    # Remove any comments, that might be in there
1267    data = re.sub(r'/\*.*\*/', '', data)
1268
1269    return data
1270
1271
1272def Parse(file):
1273    """
1274    Parses the input file and returns C code and corresponding header file.
1275    """
1276
1277    entities = []
1278
1279    while 1:
1280        # Just gets the whole struct nicely formatted
1281        data = GetNextStruct(file)
1282
1283        if not data:
1284            break
1285
1286        entities.extend(ProcessStruct(data))
1287
1288    return entities
1289
1290def GuardName(name):
1291    name = '_'.join(name.split('.'))
1292    name = '_'.join(name.split('/'))
1293    guard = '_'+name.upper()+'_'
1294
1295    return guard
1296
1297def HeaderPreamble(name):
1298    guard = GuardName(name)
1299    pre = (
1300        '/*\n'
1301        ' * Automatically generated from %s\n'
1302        ' */\n\n'
1303        '#ifndef %s\n'
1304        '#define %s\n\n' ) % (
1305        name, guard, guard)
1306
1307    # insert stdint.h - let's hope everyone has it
1308    pre += (
1309        '#include <event-config.h>\n'
1310        '#ifdef _EVENT_HAVE_STDINT_H\n'
1311        '#include <stdint.h>\n'
1312        '#endif\n' )
1313
1314    for statement in headerdirect:
1315        pre += '%s\n' % statement
1316    if headerdirect:
1317        pre += '\n'
1318
1319    pre += (
1320        '#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)\n'
1321        '#ifdef __GNUC__\n'
1322        '#define EVTAG_ASSIGN(msg, member, args...) '
1323        '(*(msg)->base->member##_assign)(msg, ## args)\n'
1324        '#define EVTAG_GET(msg, member, args...) '
1325        '(*(msg)->base->member##_get)(msg, ## args)\n'
1326        '#else\n'
1327        '#define EVTAG_ASSIGN(msg, member, ...) '
1328        '(*(msg)->base->member##_assign)(msg, ## __VA_ARGS__)\n'
1329        '#define EVTAG_GET(msg, member, ...) '
1330        '(*(msg)->base->member##_get)(msg, ## __VA_ARGS__)\n'
1331        '#endif\n'
1332        '#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)\n'
1333        '#define EVTAG_LEN(msg, member) ((msg)->member##_length)\n'
1334        )
1335
1336    return pre
1337
1338
1339def HeaderPostamble(name):
1340    guard = GuardName(name)
1341    return '#endif  /* %s */' % guard
1342
1343def BodyPreamble(name):
1344    global _NAME
1345    global _VERSION
1346
1347    header_file = '.'.join(name.split('.')[:-1]) + '.gen.h'
1348
1349    pre = ( '/*\n'
1350            ' * Automatically generated from %s\n'
1351            ' * by %s/%s.  DO NOT EDIT THIS FILE.\n'
1352            ' */\n\n' ) % (name, _NAME, _VERSION)
1353    pre += ( '#include <sys/types.h>\n'
1354             '#ifdef _EVENT_HAVE_SYS_TIME_H\n'
1355             '#include <sys/time.h>\n'
1356             '#endif\n'
1357             '#include <stdlib.h>\n'
1358             '#include <string.h>\n'
1359             '#include <assert.h>\n'
1360             '#define EVENT_NO_STRUCT\n'
1361             '#include <event.h>\n\n'
1362             '#ifdef _EVENT___func__\n'
1363             '#define __func__ _EVENT___func__\n'
1364             '#endif\n' )
1365
1366    for statement in cppdirect:
1367        pre += '%s\n' % statement
1368
1369    pre += '\n#include "%s"\n\n' % header_file
1370
1371    pre += 'void event_err(int eval, const char *fmt, ...);\n'
1372    pre += 'void event_warn(const char *fmt, ...);\n'
1373    pre += 'void event_errx(int eval, const char *fmt, ...);\n'
1374    pre += 'void event_warnx(const char *fmt, ...);\n\n'
1375
1376    return pre
1377
1378def main(argv):
1379    if len(argv) < 2 or not argv[1]:
1380        print >>sys.stderr, 'Need RPC description file as first argument.'
1381        sys.exit(1)
1382
1383    filename = argv[1]
1384
1385    ext = filename.split('.')[-1]
1386    if ext != 'rpc':
1387        print >>sys.stderr, 'Unrecognized file extension: %s' % ext
1388        sys.exit(1)
1389
1390    print >>sys.stderr, 'Reading \"%s\"' % filename
1391
1392    fp = open(filename, 'r')
1393    entities = Parse(fp)
1394    fp.close()
1395
1396    header_file = '.'.join(filename.split('.')[:-1]) + '.gen.h'
1397    impl_file = '.'.join(filename.split('.')[:-1]) + '.gen.c'
1398
1399    print >>sys.stderr, '... creating "%s"' % header_file
1400    header_fp = open(header_file, 'w')
1401    print >>header_fp, HeaderPreamble(filename)
1402
1403    # Create forward declarations: allows other structs to reference
1404    # each other
1405    for entry in entities:
1406        entry.PrintForwardDeclaration(header_fp)
1407    print >>header_fp, ''
1408
1409    for entry in entities:
1410        entry.PrintTags(header_fp)
1411        entry.PrintDeclaration(header_fp)
1412    print >>header_fp, HeaderPostamble(filename)
1413    header_fp.close()
1414
1415    print >>sys.stderr, '... creating "%s"' % impl_file
1416    impl_fp = open(impl_file, 'w')
1417    print >>impl_fp, BodyPreamble(filename)
1418    for entry in entities:
1419        entry.PrintCode(impl_fp)
1420    impl_fp.close()
1421
1422if __name__ == '__main__':
1423    main(sys.argv)
1424