1#!/usr/bin/env python
2
3import sys
4import os
5
6sys.path.insert(0, os.path.normpath(os.path.join(__file__, '../../..')))
7
8import struct
9from random import randint, choice, seed
10
11from Xlib.protocol import request, structs, rq, event
12from Xlib import X
13
14
15
16seed(42)
17
18MINI_DEF = (('CARD8', 'reqType'),
19            ('BYTE', 'pad'),
20            ('CARD16', 'length'))
21
22RESOURCE_DEF = (('CARD8', 'reqType'),
23                ('BYTE', 'pad'),
24                ('CARD16', 'length'),
25                ('CARD32', 'id'))
26
27def read_defs():
28    global request_defs, reply_defs, struct_defs
29    global mini_request_defs, resource_request_defs
30    global event_defs
31
32    request_defs = {}
33    mini_request_defs = {}
34    resource_request_defs = {}
35    reply_defs = {}
36    struct_defs = {}
37    event_defs = {}
38
39    for line in sys.stdin.readlines():
40        parts = line.strip().split()
41
42        fields = []
43        for f in parts[2:]:
44            fields.append(f.split(':'))
45
46        if parts[0] == 'REQUEST':
47            request_defs[parts[1]] = fields
48        elif parts[0] == 'MINIREQUEST':
49            mini_request_defs[parts[1]] = MINI_DEF
50        elif parts[0] == 'RESOURCEREQUEST':
51            resource_request_defs[parts[1]] = RESOURCE_DEF
52        elif parts[0] == 'REPLY':
53            reply_defs[parts[1]] = fields
54        elif parts[0] == 'STRUCT':
55            struct_defs[parts[1]] = fields
56        elif parts[0] == 'EVENT':
57            event_defs[parts[1]] = fields
58
59
60def build():
61    if struct.unpack('BB', struct.pack('H', 0x0100))[0]:
62        endian = 'be'
63    else:
64        endian = 'le'
65
66    read_defs()
67
68    build_request(endian)
69    build_event(endian)
70
71
72def build_request(endian):
73    fc = open('genrequest.c', 'w')
74
75    fc.write(C_HEADER)
76
77    reqlist = list(request.major_codes.items())
78    reqlist.sort(key=lambda x: x[0])
79
80    genfuncs = []
81    req_args = {}
82    reply_args = {}
83
84    for code, req in reqlist:
85        name = req.__name__
86        creqname = name
87
88        cdefs = request_defs.get(name)
89        if cdefs is None:
90            cdefs = mini_request_defs.get(name)
91            creqname = ''
92        if cdefs is None:
93            cdefs = resource_request_defs.get(name)
94            creqname = 'Resource'
95
96        creqname = 'x%sReq' % creqname
97
98        if cdefs is None:
99            sys.stderr.write('missing def for request: %s\n' % name)
100        else:
101            vardefs = request_var_defs.get(name, [()])
102            if type(vardefs) is not list:
103                vardefs = [vardefs]
104
105            i = 0
106            for v in vardefs:
107                if i > 0:
108                    uname = name + str(i)
109                else:
110                    uname = name
111
112                try:
113                    req_args[uname] = gen_func(fc,
114                                              'genrequest_' + uname,
115                                              creqname,
116                                              'REQUEST ' + uname,
117                                              req._request,
118                                              cdefs,
119                                              v)
120                except:
121                    sys.stderr.write('Error in %s request\n' % uname)
122                    raise
123
124                genfuncs.append('genrequest_' + uname)
125                i = i + 1
126
127        if issubclass(req, rq.ReplyRequest):
128            cdefs = reply_defs.get(name)
129
130            if cdefs is None:
131                sys.stderr.write('missing def for reply: %s\n' % name)
132            else:
133                vardefs = reply_var_defs.get(name, ())
134                if type(vardefs) is not list:
135                    vardefs = [vardefs]
136
137                i = 0
138                for v in vardefs:
139                    if i > 0:
140                        uname = name + str(i)
141                    else:
142                        uname = name
143
144                    try:
145                        reply_args[uname] = gen_func(fc,
146                                                     'genreply_' + uname,
147                                                     'x%sReply' % name,
148                                                     'REPLY ' + uname,
149                                                     req._reply,
150                                                     cdefs,
151                                                     v)
152                    except:
153                        sys.stderr.write('Error in %s reply\n' % uname)
154                        raise
155
156                    genfuncs.append('genreply_' + uname)
157                    i = i + 1
158
159
160    fc.write('''
161
162    int main(void)
163    {
164    ''')
165
166    for gf in genfuncs:
167        fc.write('      %s();\n' % gf)
168
169    fc.write('''
170      return 0;
171    }
172    ''')
173
174    fc.close()
175    os.system('gcc -Wall -g genrequest.c -o genrequest')
176
177    req_bins = {}
178    reply_bins = {}
179    pc = os.popen('./genrequest', 'r')
180    for line in pc.readlines():
181        parts = line.strip().split()
182        if parts[0] == 'REQUEST':
183            req_bins[parts[1]] = parts[2]
184        elif parts[0] == 'REPLY':
185            reply_bins[parts[1]] = parts[2]
186
187    fpy = open('../test_requests_%s.py' % endian, 'w')
188    os.chmod('../test_requests_%s.py' % endian, 0o755)
189
190    if endian == 'be':
191        e = 'BigEndian'
192        v = 1
193    else:
194        e = 'LittleEndian'
195        v = 0
196
197    fpy.write(PY_HEADER % { 'endname': e, 'endvalue': v })
198
199    for code, req in reqlist:
200        name = req.__name__
201
202        fpy.write('\n\nclass Test%s(EndianTest):\n' % name)
203        fpy.write('    def setUp(self):\n')
204
205        i = 0
206        reqs = -1
207        replies = -1
208        while 1:
209            if i > 0:
210                uname = name + str(i)
211            else:
212                uname = name
213
214            reqbin = req_bins.get(uname)
215            replybin = reply_bins.get(uname)
216
217            if reqbin is None and replybin is None:
218                break
219
220            if reqbin:
221                reqs = i
222                fpy.write('        self.req_args_%d = %s\n'
223                          % (i, build_args(req_args[uname])))
224                fpy.write('        self.req_bin_%d = %s\n\n'
225                          % (i, build_bin(reqbin)))
226            if replybin:
227                replies = i
228                fpy.write('        self.reply_args_%d = %s\n'
229                          % (i, build_args(reply_args[uname])))
230                fpy.write('        self.reply_bin_%d = %s\n\n'
231                          % (i, build_bin(replybin)))
232
233            i = i + 1
234
235        for i in range(0, reqs + 1):
236            fpy.write('''
237    def testPackRequest%(n)d(self):
238        bin = request.%(req)s._request.to_binary(*(), **self.req_args_%(n)d)
239        self.assertBinaryEqual(bin, self.req_bin_%(n)d)
240
241    def testUnpackRequest%(n)d(self):
242        args, remain = request.%(req)s._request.parse_binary(self.req_bin_%(n)d, dummy_display, 1)
243        self.assertBinaryEmpty(remain)
244        self.assertEqual(args, self.req_args_%(n)d)
245''' % { 'req': req.__name__, 'n': i })
246
247        for i in range(0, replies + 1):
248            fpy.write('''
249    def testPackReply%(n)d(self):
250        bin = request.%(req)s._reply.to_binary(*(), **self.reply_args_%(n)d)
251        self.assertBinaryEqual(bin, self.reply_bin_%(n)d)
252
253    def testUnpackReply%(n)d(self):
254        args, remain = request.%(req)s._reply.parse_binary(self.reply_bin_%(n)d, dummy_display, 1)
255        self.assertBinaryEmpty(remain)
256        self.assertEqual(args, self.reply_args_%(n)d)
257''' % { 'req': req.__name__, 'n': i })
258
259    fpy.write('''
260
261if __name__ == "__main__":
262    unittest.main()
263''')
264
265
266def build_event(endian):
267    fc = open('genevent.c', 'w')
268
269    fc.write(C_HEADER)
270
271    evtlist = list(event.event_class.items())
272    evtlist.sort(key=lambda x: x[0])
273
274    genfuncs = []
275    evt_args = {}
276
277    for code, evt in evtlist:
278
279        # skip events that does not subclass rq.Event immediately,
280        # since those are specializations of the more general ones we
281        # test.
282
283        if evt.__bases__ != (rq.Event, ):
284            continue
285
286        # special handling of KeymapNotify, since that
287        # event is so different
288        if evt == event.KeymapNotify:
289            evt_args['KeymapNotify'] = gen_func(fc,
290                                                'genevent_KeymapNotify',
291                                                'xKeymapEvent',
292                                                'EVENT KeymapNotify',
293                                                evt._fields,
294                                                (('BYTE', 'type'), ),
295                                                (31, ))
296            genfuncs.append('genevent_KeymapNotify')
297            continue
298
299        name = evt.__name__
300
301        cdefs = event_defs.get(name)
302        if cdefs is None:
303            sys.stderr.write('missing def for event: %s\n' % name)
304        else:
305            vardefs = event_var_defs.get(name, [()])
306            if type(vardefs) is not list:
307                vardefs = [vardefs]
308
309            i = 0
310            for v in vardefs:
311                if i > 0:
312                    uname = name + str(i)
313                else:
314                    uname = name
315
316                try:
317                    evt_args[uname] = gen_func(fc,
318                                               'genevent_' + uname,
319                                               'xEvent',
320                                               'EVENT ' + uname,
321                                               evt._fields,
322                                               cdefs,
323                                               v)
324                except:
325                    sys.stderr.write('Error in %s event\n' % uname)
326                    raise
327
328                genfuncs.append('genevent_' + uname)
329                i = i + 1
330
331    fc.write('''
332
333    int main(void)
334    {
335    ''')
336
337    for gf in genfuncs:
338        fc.write('      %s();\n' % gf)
339
340    fc.write('''
341      return 0;
342    }
343    ''')
344
345    fc.close()
346    os.system('gcc -Wall -g genevent.c -o genevent')
347
348    evt_bins = {}
349    pc = os.popen('./genevent', 'r')
350    for line in pc.readlines():
351        parts = line.strip().split()
352        if parts[0] == 'EVENT':
353            evt_bins[parts[1]] = parts[2]
354
355    fpy = open('../test_events_%s.py' % endian, 'w')
356    os.chmod('../test_events_%s.py' % endian, 0o755)
357
358    if endian == 'be':
359        e = 'BigEndian'
360        v = 1
361    else:
362        e = 'LittleEndian'
363        v = 0
364
365    fpy.write(PY_HEADER % { 'endname': e, 'endvalue': v })
366
367    for code, evt in evtlist:
368        if evt.__bases__ != (rq.Event, ):
369            continue
370
371        name = evt.__name__
372
373        fpy.write('\n\nclass Test%s(EndianTest):\n' % name)
374        fpy.write('    def setUp(self):\n')
375
376        i = 0
377        evts = -1
378        while 1:
379            if i > 0:
380                uname = name + str(i)
381            else:
382                uname = name
383
384            evtbin = evt_bins.get(uname)
385
386            if evtbin is None:
387                break
388
389            evts = i
390            fpy.write('        self.evt_args_%d = %s\n'
391                      % (i, build_args(evt_args[uname])))
392            fpy.write('        self.evt_bin_%d = %s\n\n'
393                      % (i, build_bin(evtbin)))
394            i = i + 1
395
396        for i in range(0, evts + 1):
397            fpy.write('''
398    def testPack%(n)d(self):
399        bin = event.%(evt)s._fields.to_binary(*(), **self.evt_args_%(n)d)
400        self.assertBinaryEqual(bin, self.evt_bin_%(n)d)
401
402    def testUnpack%(n)d(self):
403        args, remain = event.%(evt)s._fields.parse_binary(self.evt_bin_%(n)d, dummy_display, 1)
404        self.assertBinaryEmpty(remain)
405        self.assertEqual(args, self.evt_args_%(n)d)
406''' % { 'evt': evt.__name__, 'n': i })
407
408    fpy.write('''
409
410if __name__ == "__main__":
411    unittest.main()
412''')
413
414
415def gen_func(fc, funcname, structname, outputname, pydef, cdef, vardefs):
416    fc.write('''void %s(void)
417    {
418      struct {
419        %s xstruct;
420        ''' % (funcname, structname))
421
422    args = {}
423    varfs = {}
424    extra_vars = []
425    flags = None
426
427    # structure fields etc
428    i = 0
429    for f in pydef.var_fields:
430        #
431        # List of something
432        #
433        if isinstance(f, rq.List):
434            #
435            # List of short strings
436            #
437            if f.type is rq.Str:
438                vfstrings = vardefs[i]
439                vflen = 0
440                vfdata = ''
441                for s in vfstrings:
442                    vflen = vflen + 1 + len(s)
443                    vfdata = vfdata + chr(len(s)) + s
444
445                fc.write('unsigned char %s[%d];\n      '
446                         % (f.name, pad4(vflen)))
447                varfs[f.name] = ('memcpy(data.%s, %s, %d);'
448                                 % (f.name, cstring(vfdata), vflen),
449                                 len(vfstrings), 0)
450                args[f.name] = vfstrings
451
452            #
453            # List of scalars
454            #
455            elif isinstance(f.type, rq.ScalarObj) \
456                 or isinstance(f.type, rq.ResourceObj):
457
458                vflen = vardefs[i]
459
460                if f.type.structcode == 'B':
461                    rmin = 128
462                    rmax = 255
463                    deflen = pad4(vflen)
464                    ctype = 'CARD8'
465                elif f.type.structcode == 'H':
466                    rmin = 32768
467                    rmax = 65536
468                    deflen = vflen + vflen % 2
469                    ctype = 'CARD16'
470                elif f.type.structcode == 'L':
471                    rmin = 65536
472                    rmax = 2147483646
473                    deflen = vflen
474                    ctype = 'CARD32'
475                else:
476                    RuntimeError('oops: %s' % f.type.structcode)
477
478                def rand(x, rmin = rmin, rmax = rmax):
479                    return randint(rmin, rmax)
480
481                vfdata = list(map(rand, range(0, vflen)))
482
483                #
484                # Special case for a few in-line coded lists
485                #
486                if structname in ('xGetKeyboardControlReply',
487                                  'xQueryKeymapReply',
488                                  'xKeymapEvent'):
489                    extra_vars.append('%s %s_def[%d] = { %s };'
490                                      % (ctype, f.name, vflen,
491                                         ', '.join(map(str, vfdata))))
492                    varfs[f.name] = ('memcpy(data.xstruct.map, %s_def, sizeof(%s_def));'
493                                     % (f.name, f.name),
494                                     vflen, 0)
495                else:
496                    fc.write('%s %s[%d];\n      '
497                             % (ctype, f.name, deflen))
498                    extra_vars.append('%s %s_def[%d] = { %s };'
499                                      % (ctype, f.name, vflen,
500                                         ', '.join(map(str, vfdata))))
501                    varfs[f.name] = ('memcpy(data.%s, %s_def, sizeof(%s_def));'
502                                     % (f.name, f.name, f.name),
503                                     vflen, 0)
504
505                args[f.name] = vfdata
506
507            #
508            # Special handling of unique Host case
509            #
510            elif f.type is structs.Host:
511                pydata = [{ 'family': X.FamilyInternet,
512                            'name': [ 34, 23, 178, 12 ] },
513                          { 'family': X.FamilyInternet,
514                            'name': [ 130, 236, 254, 15 ] }, ]
515
516                cdata = []
517                for p in pydata:
518                    cdata.append("{ { %d, 0, 4 }, { %d, %d, %d, %d } }"
519                                 % ((p['family'], ) + tuple(p['name'])))
520
521                fc.write('struct { xHostEntry e; CARD8 name[4]; } %s[2];\n      ' % f.name)
522
523                extra_vars.append('struct { xHostEntry e; CARD8 name[4]; } %s_def[%d] = { %s };'
524                                  % (f.name, len(pydata),
525                                     ', '.join(cdata)))
526
527                varfs[f.name] = ('memcpy(data.%s, %s_def, sizeof(%s_def));'
528                                 % (f.name, f.name, f.name),
529                                 len(pydata), 0)
530
531                args[f.name] = pydata
532
533
534            #
535            # List of structures
536            #
537            elif isinstance(f.type, rq.Struct):
538                vfname, vflen = vardefs[i]
539                vfdef = struct_defs[vfname]
540
541                pydata = []
542                defdata = []
543                for si in range(0, vflen):
544                    d = []
545                    for t, cf in vfdef:
546                        if cf[:3] != 'pad':
547                            d.append(gen_value(t))
548
549                    pyd = {}
550                    for sj in range(0, len(d)):
551                        pyd[f.type.fields[sj].name] = d[sj]
552
553                    pydata.append(pyd)
554                    defdata.append('{ ' + ', '.join(map(str, d)) + ' }')
555
556                fc.write('x%s %s[%d];\n        ' % (vfname, f.name, vflen))
557
558                extra_vars.append('x%s %s_def[%d] = { %s };'
559                                  % (vfname, f.name, vflen,
560                                     ', '.join(defdata)))
561                varfs[f.name] = ('memcpy(data.%s, %s_def, sizeof(%s_def));'
562                                 % (f.name, f.name, f.name),
563                                 vflen, 0)
564                args[f.name] = pydata
565
566        #
567        # wide-char string
568        #
569        elif isinstance(f, rq.String16):
570            vfstr = vardefs[i]
571            vflen = len(vfstr)
572
573            fc.write('unsigned char %s[%d];\n        ' %
574                     (f.name, (vflen + vflen % 2) * 2))
575
576            s = ''
577            for c in vfstr:
578                s = s + '\0' + c
579
580            varfs[f.name] = ('memcpy(data.%s, %s, %d);'
581                             % (f.name, cstring(s), vflen * 2),
582                             vflen, 0)
583            args[f.name] = tuple(map(ord, vfstr))
584
585        #
586        # byte-char string
587        #
588        elif isinstance(f, (rq.String8, rq.Binary)):
589            vfstr = vardefs[i]
590            vflen = len(vfstr)
591
592            fc.write('unsigned char %s[%d];\n        ' %
593                     (f.name, (vflen + (4 - vflen % 4) % 4)))
594            varfs[f.name] = ('memcpy(data.%s, %s, %d);'
595                             % (f.name, cstring(vfstr), vflen),
596                             vflen, 0)
597            args[f.name] = vfstr
598
599        #
600        # List of optional values
601        #
602        elif isinstance(f, rq.ValueList):
603            vlcode = []
604            vlargs = {}
605            flags = 0
606            for vlf, flag in f.fields:
607                ctype, rmin, rmax, clen = structcode_defs[vlf.structcode]
608                fc.write('%s %s_%s;\n      '
609                         % (ctype, f.name, vlf.name))
610                if clen < 4:
611                    fc.write('unsigned char %s_%s_pad[%d];\n      '
612                             % (f.name, vlf.name, 4 - clen))
613
614                if isinstance(vlf, rq.Set):
615                    val = choice(vlf.values)
616                elif isinstance(vlf, rq.Bool):
617                    val = choice((0, 1))
618                else:
619                    val = randint(rmin, rmax)
620                vlargs[vlf.name] = val
621                vlcode.append('data.%s_%s = %d;' % (f.name, vlf.name, val))
622                flags = flags | flag
623
624            # vlcode.append('data.%s_flags = %d;' % (f.name, flags))
625
626            varfs[f.name] = (' '.join(vlcode), 0, 0)
627            args[f.name] = vlargs
628
629        #
630        # Text/font list, hardwire since they are so rare
631        #
632        elif isinstance(f, rq.TextElements8):
633            if isinstance(f, rq.TextElements16):
634                vfstr = b'\x02\x02\x10\x23\x00\x12\xff\x01\x02\x03\x04'
635                ret = [{'delta': 2, 'string': (0x1023, 0x0012)},
636                       0x01020304]
637            else:
638                vfstr = b'\x03\x02zoo\xff\x01\x02\x03\x04\x02\x00ie'
639                ret = [{'delta': 2, 'string': 'zoo'},
640                       0x01020304,
641                       { 'delta': 0, 'string': 'ie'}]
642
643            fc.write('unsigned char %s[%d];\n      '
644                     % (f.name, len(vfstr)))
645            varfs[f.name] = ('memcpy(data.%s, %s, %d);'
646                             % (f.name, cstring(vfstr), len(vfstr)),
647                             0, 0)
648            args[f.name] = ret
649
650        #
651        # Keyboard/modifier mappings
652        #
653        elif isinstance(f, rq.KeyboardMapping) \
654             or isinstance(f, rq.ModifierMapping):
655
656            if isinstance(f, rq.KeyboardMapping):
657                rmin = 0
658                rmax = 2147483646
659                length = 20
660                format = 3
661                ctype = 'CARD32'
662            else:
663                rmin = 0
664                rmax = 255
665                length = 8
666                format = 2
667                ctype = 'CARD8'
668
669            pydata = []
670            cdata = []
671            for i in range(0, length):
672                x = []
673                for j in range(0, format):
674                    v = randint(rmin, rmax)
675                    x.append(v)
676                    cdata.append(str(v))
677                pydata.append(x)
678
679            fc.write('%s %s[%d];\n      ' % (ctype, f.name, len(cdata)))
680            extra_vars.append('%s %s_def[%d] = { %s };'
681                              % (ctype, f.name, len(cdata),
682                                 ', '.join(cdata)))
683            varfs[f.name] = ('memcpy(data.%s, %s_def, sizeof(%s_def));'
684                             % (f.name, f.name, f.name),
685                             length, format)
686            args[f.name] = pydata
687
688        #
689        # property data
690        #
691        elif isinstance(f, rq.PropertyData):
692            format, data = vardefs[i]
693            length = len(data)
694
695            if format == 8:
696                ctype = 'CARD8'
697                clen = pad4(length)
698                cdata = cstring(data)
699            elif format == 16:
700                ctype = 'CARD16'
701                clen = length + length % 2
702                cdata = ', '.join(map(str, data))
703            elif format == 32:
704                ctype = 'CARD32'
705                clen = length
706                cdata = ', '.join(map(str, data))
707
708            if not isinstance(f, rq.FixedPropertyData):
709                fc.write('%s %s[%d];\n        ' %
710                         (ctype, f.name, clen))
711
712            extra_vars.append('%s %s_def[%d] = { %s };'
713                              % (ctype, f.name, length, cdata))
714
715            if not isinstance(f, rq.FixedPropertyData):
716                varfs[f.name] = ('memcpy(data.%s, %s_def, sizeof(%s_def));'
717                                 % (f.name, f.name, f.name),
718                                 length, format)
719            else:
720                varfs[f.name] = ('assert(sizeof(%s_def) == 20); memcpy(data.xstruct.u.clientMessage.u.b.bytes, %s_def, sizeof(%s_def));'
721                                 % (f.name, f.name, f.name),
722                                 length, format)
723
724            args[f.name] = (format, data)
725
726        #
727        # Event
728        #
729        elif isinstance(f, rq.EventField):
730            ev = event.Expose(window = gen_value('CARD32'),
731                              x = gen_value('CARD16'),
732                              y =  gen_value('CARD16'),
733                              width = gen_value('CARD16'),
734                              height = gen_value('CARD16'),
735                              count = gen_value('CARD16'))
736            cdata = cstring(ev._binary)
737
738            # fc.write('unsigned char %s[32];\n        ' % f.name)
739            extra_vars.append('unsigned char %s_def[32] = %s;'
740                              % (f.name, cdata))
741            varfs[f.name] = ('memcpy(&data.xstruct.event, %s_def, sizeof(%s_def));'
742                             % (f.name, f.name),
743                             0, 0)
744
745            args[f.name] = ev
746
747        else:
748            raise RuntimeError('oops: %s.%s' % (funcname, f.name))
749
750        i = i + 1
751
752
753    fc.write('\n      } data;\n')
754
755
756    for v in extra_vars:
757        fc.write('      %s\n' % v)
758
759    fc.write('''
760      memset(&data, 0, sizeof(data));
761
762    ''')
763
764    pyi = 0
765    ci = 0
766
767    while ci < len(cdef):
768        try:
769            pyf = pydef.fields[pyi]
770        except IndexError:
771            pyf = None
772
773        cf = cdef[ci]
774        t, f = cf
775
776        pyi = pyi + 1
777        ci = ci + 1
778
779        if f[:3] == 'pad' or f[:6] == 'walign':
780            if not isinstance(pyf, rq.Pad):
781                pyi = pyi - 1
782
783        # special case for value list mask
784        elif (f == 'mask' or f == 'valueMask') and flags is not None:
785            fc.write('      data.xstruct.%s = %d;\n' % (f, flags))
786
787        elif isinstance(pyf, rq.ConstantField):
788            fc.write('      data.xstruct.%s = %d;\n' % (f, pyf.value))
789
790        elif isinstance(pyf, rq.RequestLength):
791            assert f == 'length'
792
793            fc.write('      assert(sizeof(data) % 4 == 0);\n')
794            fc.write('      data.xstruct.length = sizeof(data) / 4;\n')
795
796        elif isinstance(pyf, rq.ReplyLength):
797            assert f == 'length'
798
799            fc.write('      assert(sizeof(data) % 4 == 0);\n')
800            fc.write('      assert(sizeof(data) >= 32);\n')
801            fc.write('      data.xstruct.length = (sizeof(data) - 32) / 4;\n')
802
803        elif isinstance(pyf, rq.LengthOf):
804            fc.write('      data.xstruct.%s = %d;\n' % (f, varfs[pyf.name][1]))
805
806        elif isinstance(pyf, rq.OddLength):
807            fc.write('      data.xstruct.%s = %d;\n' % (f, varfs[pyf.name][1] % 2))
808
809        elif isinstance(pyf, rq.Format):
810            fc.write('      data.xstruct.%s = %d;\n' % (f, varfs[pyf.name][2]))
811
812        elif isinstance(pyf, rq.Set):
813            val = choice(pyf.values)
814            fc.write('      data.xstruct.%s = %d;\n' % (f, val))
815            args[pyf.name] = val
816
817        elif t == 'xCharInfo':
818            d = []
819            for ct, cf in struct_defs['CharInfo']:
820                if cf[:3] != 'pad':
821                    d.append(gen_value(ct))
822
823            pyd = {}
824            for sj in range(0, len(d)):
825                pyd[pyf.type.fields[sj].name] = d[sj]
826
827            fc.write('{ %s def = { %s };\n      '
828                     % (t, ', '.join(map(str, d))))
829            fc.write('memcpy(&data.xstruct.%s, &def, sizeof(def)); }\n        ' % f)
830            args[pyf.name] = pyd
831
832        else:
833            val = gen_value(t)
834            fc.write('      data.xstruct.%s = %d;\n' % (f, val))
835            args[pyf.name] = val
836
837    for code, length, format in varfs.values():
838        fc.write('      %s\n' % code);
839
840    fc.write('''
841      output("%s", &data, sizeof(data));
842    }
843
844    ''' % outputname)
845
846    return args
847
848
849def gen_value(t):
850    if t == 'INT8':
851        val = randint(-128, -1)
852    elif t == 'INT16':
853        val = randint(-32768, -256)
854    elif t == 'INT32':
855        val = randint(-2147483647, -65536)
856    elif t == 'CARD8' or t == 'BYTE':
857        val = randint(128, 255)
858    elif t == 'CARD16':
859        val = randint(256, 65535)
860    elif t == 'CARD32':
861        val = randint(65536, 2147483646)
862    elif t == 'BOOL':
863        val = randint(0, 1)
864    else:
865        raise RuntimeError('unknown type: %s' % t)
866    return val
867
868
869def pad4(l):
870    return l + (4 - l % 4) % 4
871
872def cstring(s):
873    if not isinstance(s, bytes):
874        s = s.encode('ascii')
875    return '"' + ''.join('\\x%x' % c for c in s) + '"'
876
877
878def build_args(args):
879    kwlist = []
880    for kw, val in sorted(args.items(), key=lambda i: i[0]):
881        if isinstance(val, rq.Event):
882            members = list(val._data.keys())
883            members.remove('send_event')
884            kwlist.append("            '%s': event.%s(%s),\n" % (
885                kw, val.__class__.__name__,
886                ', '.join('%s=%s' % (m, val._data[m])
887                          for m in sorted(members)),
888            ))
889        else:
890            kwlist.append("            '%s': %s,\n" % (kw, repr(val)))
891
892    return '{\n' + ''.join(kwlist) + '            }'
893
894def build_bin(bin):
895    bins = []
896    for i in range(0, len(bin), 16):
897        bins.append(bin[i:i+16])
898
899    bins2 = []
900    for i in range(0, len(bins), 2):
901        try:
902            bins2.append("b'%s' b'%s'" % (bins[i], bins[i + 1]))
903        except IndexError:
904            bins2.append("b'%s'" % bins[i])
905
906    return ' \\\n            '.join(bins2)
907
908
909request_var_defs = {
910    'InternAtom': ('fuzzy_prop', ),
911    'ChangeProperty': [((8, b''), ),
912                       ((8, b'foo'), ),
913                       ((8, b'zoom'), ),
914                       ((16, []), ),
915                       ((16, [1, 2, 3]), ),
916                       ((16, [1, 2, 3, 4]), ),
917                       ((32, []), ),
918                       ((32, [1, 2, 3]), ) ],
919    'OpenFont': ('foofont', ),
920    'QueryTextExtents': ('foo', ),
921    'ListFonts': ('bhazr', ),
922    'ListFontsWithInfo': ('bhazr2', ),
923    'SetFontPath': [(['foo', 'bar', 'gazonk'], ),
924                    ([], ) ],
925    'SetDashes': (9, ),
926    'SetClipRectangles': [(('Rectangle', 2), ),
927                          (('Rectangle', 0), ) ],
928    'PolyPoint': (('Point', 3), ),
929    'PolyLine': (('Point', 5), ),
930    'PolySegment': (('Segment', 1), ),
931    'PolyRectangle': (('Rectangle', 3), ),
932    'PolyArc': (('Arc', 3), ),
933    'FillPoly': (('Point', 3), ),
934    'PolyFillRectangle': (('Rectangle', 2), ),
935    'PolyFillArc': (('Arc', 1), ),
936    'PutImage': (b'\xe9\x10\xf2o\x7f{\xae-\xe6\x18\xce\x83', ),
937    'ImageText8': ('showme', ),
938    'ImageText16': ('showmore', ),
939    'AllocNamedColor': ('octarin', ),
940    'FreeColors': (17, ),
941    'StoreColors': (('ColorItem', 4), ),
942    'StoreNamedColor': ('blue', ),
943    'QueryColors': [(8, ), (0, ) ],
944    'LookupColor': ('octarin', ),
945    'QueryExtension': ('XTRA', ),
946    'ChangeHosts': (4, ),
947    'RotateProperties': (12, ),
948    'SetPointerMapping': (5, ),
949    }
950
951reply_var_defs = {
952    'QueryTree': (7, ),
953    'GetAtomName': ('WM_CLASS', ),
954    'GetProperty': [((8, b''), ),
955                       ((8, b'foo'), ),
956                       ((8, b'zoom'), ),
957                       ((16, []), ),
958                       ((16, [1, 2, 3]), ),
959                       ((16, [1, 2, 3, 4]), ),
960                       ((32, []), ),
961                       ((32, [1, 2, 3]), ) ],
962    'ListProperties': (23, ),
963    'GetMotionEvents': (('Timecoord', 5), ),
964    'QueryKeymap': (32, ),
965    'QueryFont': (('FontProp', 1), ('CharInfo', 3)),
966    'ListFonts': (['fie', 'fuzzy', 'foozooom'], ),
967    'ListFontsWithInfo': (('FontProp', 1), 'fontfont'),
968    'GetFontPath': [(['path1', 'path2232'], ),
969                    ([], ) ],
970    'GetImage': (b'\xeb?:\xa7\xc6\x8b\xc2\x96o-S\xe6\xd6z6\x94\xd7v\xd2R.\xa2\xeaw\t\x13\x95\x85',),
971    'ListInstalledColormaps': (2, ),
972    'AllocColorCells': [(17, 3),
973                        (0, 0) ],
974    'AllocColorPlanes': (4, ),
975    'QueryColors': (('rgb', 5), ),
976    'ListExtensions': (['XTRA', 'XTRA-II'], ),
977    'GetKeyboardControl': (32, ),
978    'GetPointerMapping': (5, ),
979#    '': (, ),
980    }
981
982event_var_defs = {
983    'ClientMessage': [((8, b'01234567890123456789'), ),
984                      ((16, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), ),
985                      ((32, [1, 2, 3, 4, 5]), ) ],
986    }
987
988structcode_defs = {
989    'b': ('INT8', -128, -1, 1),
990    'B': ('CARD8', 128, 255, 1),
991    'h': ('INT16', -32768, -1, 2),
992    'H': ('CARD16', 32768, 65536, 2),
993    'l': ('INT32', -2147483647, -1, 4),
994    'L': ('CARD32', 65536, 2147483646, 4),
995    }
996
997C_HEADER = r'''
998#include <stdio.h>
999#include <assert.h>
1000#include <ctype.h>
1001#include <string.h>
1002#include <X11/Xproto.h>
1003
1004void output(char *name, void *data, int length)
1005{
1006    unsigned char *d = (unsigned char *) data;
1007
1008    printf("%s ", name);
1009
1010    while (length-- > 0) {
1011        if (0 && isgraph(*d))
1012            putchar(*d);
1013        else
1014            printf("\\x%02x", *d);
1015        d++;
1016    }
1017
1018    putchar('\n');
1019}
1020
1021'''
1022
1023PY_HEADER = r'''#!/usr/bin/env python2
1024
1025import sys, os
1026sys.path.insert(0, os.path.normpath(os.path.join(__file__, '../..')))
1027
1028import unittest
1029from Xlib.protocol import request, event
1030from . import %(endname)sTest as EndianTest
1031from . import DummyDisplay
1032
1033dummy_display = DummyDisplay()
1034'''
1035
1036if __name__ == '__main__':
1037    build()
1038