1#!/usr/bin/env python
2
3import sys, os, os.path as path, struct, errno
4from optparse import OptionParser
5
6def xencov_split(opts):
7    """Split input into multiple gcda files"""
8
9    # Check native byte order and explicitly specify it.  The "native"
10    # byte order in struct module takes into account padding while the
11    # data is always packed.
12    if sys.byteorder == 'little':
13        bo_prefix = '<'
14    else:
15        bo_prefix = '>'
16
17    input_file = opts.args[0]
18
19    f = open(input_file)
20
21    # Magic number
22    s = f.read(4)
23    magic, = struct.unpack(bo_prefix + "I", s)
24    # See public/sysctl.h for magic number -- "XCOV"
25    if magic != 0x58434f56:
26        raise Exception("Invalid magic number")
27
28    # The rest is zero or more records
29    content = f.read()
30
31    f.close()
32
33    while content:
34        off = content.find('\x00')
35        fmt = bo_prefix + str(off) + 's'
36        fn, = struct.unpack_from(fmt, content)
37        content = content[off+1:]
38
39        fmt = bo_prefix + 'I'
40        sz, = struct.unpack_from(fmt, content)
41        content = content[struct.calcsize(fmt):]
42
43        fmt = bo_prefix + str(sz) + 's'
44        payload, = struct.unpack_from(fmt, content)
45        content = content[sz:]
46
47        # Create and store files
48        if opts.output_dir == '.':
49            opts.output_dir = os.getcwd()
50
51        dir = opts.output_dir + path.dirname(fn)
52        try:
53            os.makedirs(dir)
54        except OSError, e:
55            if e.errno == errno.EEXIST and os.path.isdir(dir):
56                pass
57            else:
58                raise
59
60        full_path = dir + '/' + path.basename(fn)
61        f = open(full_path, "w")
62        f.write(payload)
63        f.close()
64
65def main():
66    """ Main entrypoint """
67
68    # Change stdout to be line-buffered.
69    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
70
71    parser = OptionParser(
72        usage = "%prog [OPTIONS] <INPUT>",
73        description = "Utility to split xencov data file",
74        )
75
76    parser.add_option("--output-dir", action = "store",
77                      dest = "output_dir", default = ".",
78                      type = "string",
79                      help = ('Specify the directory to place output files, '
80                              'defaults to current directory'),
81                      )
82
83    opts, args = parser.parse_args()
84    opts.args = args
85
86    xencov_split(opts)
87
88
89if __name__ == "__main__":
90    try:
91        sys.exit(main())
92    except Exception, e:
93        print >>sys.stderr, "Error:", e
94        sys.exit(1)
95    except KeyboardInterrupt:
96        sys.exit(1)
97
98