root / gr-run-waveform / gen-xyzzy @ 5a07519b
History | View | Annotate | Download (5.1 kB)
| 1 | e3ec22b1 | Eric Blossom | #!/usr/bin/env python |
|---|---|---|---|
| 2 | e3ec22b1 | Eric Blossom | |
| 3 | e3ec22b1 | Eric Blossom | """ |
| 4 | e3ec22b1 | Eric Blossom | usage: gen-xyzzy [-o output] directory... |
| 5 | e3ec22b1 | Eric Blossom | |
| 6 | e3ec22b1 | Eric Blossom | Typical usage: |
| 7 | e3ec22b1 | Eric Blossom | gen-xyzzy -o filesystem.dat /usr/share/guile/1.8 /usr/local/share/guile/site |
| 8 | e3ec22b1 | Eric Blossom | |
| 9 | e3ec22b1 | Eric Blossom | Where /usr/share/guile points to the system guile installation and |
| 10 | e3ec22b1 | Eric Blossom | /usr/local/share/guile/site points to the GNU Radio installed guile files |
| 11 | e3ec22b1 | Eric Blossom | |
| 12 | e3ec22b1 | Eric Blossom | |
| 13 | e3ec22b1 | Eric Blossom | Build a single file that contains all of the *.scm files from the |
| 14 | e3ec22b1 | Eric Blossom | guile installation and from the GR installation. I figure it's |
| 15 | e3ec22b1 | Eric Blossom | basically a table that maps strings to strings. That is, |
| 16 | e3ec22b1 | Eric Blossom | "/foo/bar/filename" -> "file contents". We could just mmap |
| 17 | e3ec22b1 | Eric Blossom | it in read-only, or just read it in. Reading is more portable, |
| 18 | e3ec22b1 | Eric Blossom | let's do that. |
| 19 | e3ec22b1 | Eric Blossom | |
| 20 | e3ec22b1 | Eric Blossom | File: [ header | directory | strings ] |
| 21 | e3ec22b1 | Eric Blossom | |
| 22 | e3ec22b1 | Eric Blossom | All integers are net-endian. |
| 23 | e3ec22b1 | Eric Blossom | |
| 24 | e3ec22b1 | Eric Blossom | struct header {
|
| 25 | e3ec22b1 | Eric Blossom | char magic[8]; |
| 26 | e3ec22b1 | Eric Blossom | |
| 27 | e3ec22b1 | Eric Blossom | uint32_t offset_to_directory; // byte offset from start of file |
| 28 | e3ec22b1 | Eric Blossom | uint32_t size_of_directory; // bytes |
| 29 | e3ec22b1 | Eric Blossom | uint32_t number_of_dir_entries; |
| 30 | e3ec22b1 | Eric Blossom | |
| 31 | e3ec22b1 | Eric Blossom | uint32_t offset_to_strings; // byte offset from start of file |
| 32 | e3ec22b1 | Eric Blossom | uint32_t size_of_strings; // bytes |
| 33 | e3ec22b1 | Eric Blossom | }; |
| 34 | e3ec22b1 | Eric Blossom | |
| 35 | e3ec22b1 | Eric Blossom | struct directory_entry {
|
| 36 | e3ec22b1 | Eric Blossom | uint32_t offset_to_name; // from start of strings |
| 37 | e3ec22b1 | Eric Blossom | uint32_t offset_to_contents; // from start of strings |
| 38 | e3ec22b1 | Eric Blossom | } |
| 39 | e3ec22b1 | Eric Blossom | |
| 40 | e3ec22b1 | Eric Blossom | Each string starts with a uint32_t length, followed by length bytes. |
| 41 | e3ec22b1 | Eric Blossom | There is no trailing \0 in the string. Each string entry is followed |
| 42 | e3ec22b1 | Eric Blossom | with enough padding to bring it up to a multiple of 4 bytes. |
| 43 | e3ec22b1 | Eric Blossom | |
| 44 | e3ec22b1 | Eric Blossom | struct string_entry {
|
| 45 | e3ec22b1 | Eric Blossom | uint32_t length; |
| 46 | e3ec22b1 | Eric Blossom | unsigned char c[1]; // 0 is nicer, but not portable. |
| 47 | e3ec22b1 | Eric Blossom | } |
| 48 | e3ec22b1 | Eric Blossom | """ |
| 49 | e3ec22b1 | Eric Blossom | |
| 50 | e3ec22b1 | Eric Blossom | |
| 51 | e3ec22b1 | Eric Blossom | from optparse import OptionParser |
| 52 | e3ec22b1 | Eric Blossom | import sys |
| 53 | e3ec22b1 | Eric Blossom | import os |
| 54 | e3ec22b1 | Eric Blossom | import os.path |
| 55 | e3ec22b1 | Eric Blossom | from pprint import pprint |
| 56 | e3ec22b1 | Eric Blossom | import struct |
| 57 | e3ec22b1 | Eric Blossom | |
| 58 | e3ec22b1 | Eric Blossom | |
| 59 | e3ec22b1 | Eric Blossom | def main(): |
| 60 | e3ec22b1 | Eric Blossom | parser = OptionParser(usage="usage: %prog [options] directory...") |
| 61 | e3ec22b1 | Eric Blossom | parser.add_option("-o", type="string", default=None, metavar="FILENAME",
|
| 62 | e3ec22b1 | Eric Blossom | help="Specify output filename [default=stdout]") |
| 63 | e3ec22b1 | Eric Blossom | (options, args) = parser.parse_args() |
| 64 | e3ec22b1 | Eric Blossom | |
| 65 | e3ec22b1 | Eric Blossom | if len(args) == 0: |
| 66 | e3ec22b1 | Eric Blossom | parser.print_help() |
| 67 | e3ec22b1 | Eric Blossom | raise SystemExit, 1 |
| 68 | e3ec22b1 | Eric Blossom | |
| 69 | e3ec22b1 | Eric Blossom | if options.o: |
| 70 | e3ec22b1 | Eric Blossom | output = open(options.o, 'wb') |
| 71 | e3ec22b1 | Eric Blossom | else: |
| 72 | e3ec22b1 | Eric Blossom | output = sys.stdout |
| 73 | e3ec22b1 | Eric Blossom | |
| 74 | e3ec22b1 | Eric Blossom | doit(output, args) |
| 75 | e3ec22b1 | Eric Blossom | |
| 76 | e3ec22b1 | Eric Blossom | |
| 77 | e3ec22b1 | Eric Blossom | def doit(output, dirs): |
| 78 | e3ec22b1 | Eric Blossom | acc = [] |
| 79 | e3ec22b1 | Eric Blossom | for d in dirs: |
| 80 | e3ec22b1 | Eric Blossom | acc.extend(handle_dir(d)) |
| 81 | e3ec22b1 | Eric Blossom | |
| 82 | e3ec22b1 | Eric Blossom | uniq = {}
|
| 83 | e3ec22b1 | Eric Blossom | for key, val in acc: |
| 84 | e3ec22b1 | Eric Blossom | if key in uniq: |
| 85 | e3ec22b1 | Eric Blossom | if val != uniq[key]: |
| 86 | e3ec22b1 | Eric Blossom | sys.stderr.write("Duplicate key: %s %s %s\n" % (key, uniq[key], val))
|
| 87 | e3ec22b1 | Eric Blossom | else: |
| 88 | e3ec22b1 | Eric Blossom | uniq[key] = val |
| 89 | e3ec22b1 | Eric Blossom | |
| 90 | e3ec22b1 | Eric Blossom | t = uniq.items() |
| 91 | e3ec22b1 | Eric Blossom | t.sort() |
| 92 | e3ec22b1 | Eric Blossom | write_xyzzy(output, t) |
| 93 | e3ec22b1 | Eric Blossom | |
| 94 | e3ec22b1 | Eric Blossom | |
| 95 | e3ec22b1 | Eric Blossom | def handle_dir(directory): |
| 96 | e3ec22b1 | Eric Blossom | if not directory.endswith(os.sep): |
| 97 | e3ec22b1 | Eric Blossom | directory = directory + os.sep |
| 98 | e3ec22b1 | Eric Blossom | acc = [] |
| 99 | e3ec22b1 | Eric Blossom | for root, dirs, files in os.walk(directory, topdown=True): |
| 100 | 350a427f | Eric Blossom | # scm_files = [f for f in files if f.endswith('.scm')]
|
| 101 | 350a427f | Eric Blossom | scm_files = files |
| 102 | e3ec22b1 | Eric Blossom | for f in scm_files: |
| 103 | e3ec22b1 | Eric Blossom | full_name = os.path.join(root, f) |
| 104 | e3ec22b1 | Eric Blossom | t = (full_name[len(directory):], full_name) |
| 105 | e3ec22b1 | Eric Blossom | acc.append(t) |
| 106 | e3ec22b1 | Eric Blossom | return acc |
| 107 | e3ec22b1 | Eric Blossom | |
| 108 | e3ec22b1 | Eric Blossom | |
| 109 | e3ec22b1 | Eric Blossom | def file_length(filename): |
| 110 | e3ec22b1 | Eric Blossom | statinfo = os.stat(filename) |
| 111 | e3ec22b1 | Eric Blossom | return statinfo.st_size |
| 112 | e3ec22b1 | Eric Blossom | |
| 113 | e3ec22b1 | Eric Blossom | |
| 114 | e3ec22b1 | Eric Blossom | # return n rounded up to a multiple of 4 |
| 115 | e3ec22b1 | Eric Blossom | def round_up(n): |
| 116 | e3ec22b1 | Eric Blossom | return (n + 3) & -4 |
| 117 | e3ec22b1 | Eric Blossom | |
| 118 | e3ec22b1 | Eric Blossom | |
| 119 | e3ec22b1 | Eric Blossom | class string_table(object): |
| 120 | e3ec22b1 | Eric Blossom | def __init__(self): |
| 121 | e3ec22b1 | Eric Blossom | self._table = '' |
| 122 | e3ec22b1 | Eric Blossom | self._padding = '\0\0\0\0' |
| 123 | e3ec22b1 | Eric Blossom | |
| 124 | e3ec22b1 | Eric Blossom | def add_string(self, s): |
| 125 | e3ec22b1 | Eric Blossom | r = len(self._table) |
| 126 | e3ec22b1 | Eric Blossom | len_s = len(s) |
| 127 | e3ec22b1 | Eric Blossom | padding = self._padding[0:round_up(len_s) - len_s] |
| 128 | e3ec22b1 | Eric Blossom | self._table = ''.join((self._table, struct.pack('>I', len(s)), s, padding))
|
| 129 | e3ec22b1 | Eric Blossom | return r |
| 130 | e3ec22b1 | Eric Blossom | |
| 131 | e3ec22b1 | Eric Blossom | |
| 132 | e3ec22b1 | Eric Blossom | def write_xyzzy(f, list_of_tuples): |
| 133 | e3ec22b1 | Eric Blossom | # tuples: (name, filename) |
| 134 | e3ec22b1 | Eric Blossom | names = [s[0] for s in list_of_tuples] |
| 135 | e3ec22b1 | Eric Blossom | number_of_dir_entries = len(list_of_tuples) |
| 136 | e3ec22b1 | Eric Blossom | number_of_names = number_of_dir_entries |
| 137 | e3ec22b1 | Eric Blossom | number_of_files = number_of_dir_entries |
| 138 | e3ec22b1 | Eric Blossom | sizeof_uint32 = 4 |
| 139 | e3ec22b1 | Eric Blossom | |
| 140 | e3ec22b1 | Eric Blossom | contents = {}
|
| 141 | e3ec22b1 | Eric Blossom | for name, filename in list_of_tuples: |
| 142 | e3ec22b1 | Eric Blossom | t = open(filename, 'rb').read() |
| 143 | e3ec22b1 | Eric Blossom | contents[name] = t |
| 144 | e3ec22b1 | Eric Blossom | |
| 145 | e3ec22b1 | Eric Blossom | offset_to_directory = 28 |
| 146 | e3ec22b1 | Eric Blossom | size_of_directory = number_of_dir_entries * 8 |
| 147 | e3ec22b1 | Eric Blossom | offset_to_strings = offset_to_directory + size_of_directory |
| 148 | e3ec22b1 | Eric Blossom | |
| 149 | e3ec22b1 | Eric Blossom | st = string_table() |
| 150 | e3ec22b1 | Eric Blossom | |
| 151 | e3ec22b1 | Eric Blossom | # Insert names in string table first to help locality |
| 152 | e3ec22b1 | Eric Blossom | name_str_offset = {}
|
| 153 | e3ec22b1 | Eric Blossom | for name in names: |
| 154 | e3ec22b1 | Eric Blossom | name_str_offset[name] = st.add_string(name) |
| 155 | e3ec22b1 | Eric Blossom | |
| 156 | e3ec22b1 | Eric Blossom | # Now add file contents |
| 157 | e3ec22b1 | Eric Blossom | content_str_offset = {}
|
| 158 | e3ec22b1 | Eric Blossom | for name in names: |
| 159 | e3ec22b1 | Eric Blossom | content_str_offset[name] = st.add_string(contents[name]) |
| 160 | e3ec22b1 | Eric Blossom | |
| 161 | e3ec22b1 | Eric Blossom | size_of_strings = len(st._table) |
| 162 | e3ec22b1 | Eric Blossom | |
| 163 | e3ec22b1 | Eric Blossom | if 0: |
| 164 | e3ec22b1 | Eric Blossom | print "offset_to_directory\t", offset_to_directory |
| 165 | e3ec22b1 | Eric Blossom | print "size_of_directory\t", size_of_directory |
| 166 | e3ec22b1 | Eric Blossom | print "number_of_dir_entries\t", number_of_dir_entries |
| 167 | e3ec22b1 | Eric Blossom | print "offset_to_strings\t", offset_to_strings |
| 168 | e3ec22b1 | Eric Blossom | print "size_of_strings\t\t", size_of_strings |
| 169 | e3ec22b1 | Eric Blossom | |
| 170 | e3ec22b1 | Eric Blossom | magic = '-XyZzY-\0' |
| 171 | e3ec22b1 | Eric Blossom | |
| 172 | e3ec22b1 | Eric Blossom | # Write header |
| 173 | e3ec22b1 | Eric Blossom | f.write(struct.pack('>8s5I',
|
| 174 | e3ec22b1 | Eric Blossom | magic, |
| 175 | e3ec22b1 | Eric Blossom | offset_to_directory, |
| 176 | e3ec22b1 | Eric Blossom | size_of_directory, |
| 177 | e3ec22b1 | Eric Blossom | number_of_dir_entries, |
| 178 | e3ec22b1 | Eric Blossom | offset_to_strings, |
| 179 | e3ec22b1 | Eric Blossom | size_of_strings)) |
| 180 | e3ec22b1 | Eric Blossom | |
| 181 | e3ec22b1 | Eric Blossom | # Write directory |
| 182 | e3ec22b1 | Eric Blossom | for name in names: |
| 183 | e3ec22b1 | Eric Blossom | f.write(struct.pack('>2I',
|
| 184 | e3ec22b1 | Eric Blossom | name_str_offset[name], |
| 185 | e3ec22b1 | Eric Blossom | content_str_offset[name])) |
| 186 | e3ec22b1 | Eric Blossom | |
| 187 | e3ec22b1 | Eric Blossom | # Write string table |
| 188 | e3ec22b1 | Eric Blossom | f.write(st._table) |
| 189 | e3ec22b1 | Eric Blossom | |
| 190 | e3ec22b1 | Eric Blossom | |
| 191 | e3ec22b1 | Eric Blossom | if __name__ == "__main__": |
| 192 | e3ec22b1 | Eric Blossom | main() |