diff options
Diffstat (limited to 'gr-run-waveform/gen-xyzzy')
-rw-r--r-- | gr-run-waveform/gen-xyzzy | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/gr-run-waveform/gen-xyzzy b/gr-run-waveform/gen-xyzzy new file mode 100644 index 000000000..955d24798 --- /dev/null +++ b/gr-run-waveform/gen-xyzzy @@ -0,0 +1,192 @@ +#!/usr/bin/env python + +""" + usage: gen-xyzzy [-o output] directory... + + Typical usage: + gen-xyzzy -o filesystem.dat /usr/share/guile/1.8 /usr/local/share/guile/site + + Where /usr/share/guile points to the system guile installation and + /usr/local/share/guile/site points to the GNU Radio installed guile files + + + Build a single file that contains all of the *.scm files from the + guile installation and from the GR installation. I figure it's + basically a table that maps strings to strings. That is, + "/foo/bar/filename" -> "file contents". We could just mmap + it in read-only, or just read it in. Reading is more portable, + let's do that. + + File: [ header | directory | strings ] + + All integers are net-endian. + + struct header { + char magic[8]; + + uint32_t offset_to_directory; // byte offset from start of file + uint32_t size_of_directory; // bytes + uint32_t number_of_dir_entries; + + uint32_t offset_to_strings; // byte offset from start of file + uint32_t size_of_strings; // bytes + }; + + struct directory_entry { + uint32_t offset_to_name; // from start of strings + uint32_t offset_to_contents; // from start of strings + } + + Each string starts with a uint32_t length, followed by length bytes. + There is no trailing \0 in the string. Each string entry is followed + with enough padding to bring it up to a multiple of 4 bytes. + + struct string_entry { + uint32_t length; + unsigned char c[1]; // 0 is nicer, but not portable. + } +""" + + +from optparse import OptionParser +import sys +import os +import os.path +from pprint import pprint +import struct + + +def main(): + parser = OptionParser(usage="usage: %prog [options] directory...") + parser.add_option("-o", type="string", default=None, metavar="FILENAME", + help="Specify output filename [default=stdout]") + (options, args) = parser.parse_args() + + if len(args) == 0: + parser.print_help() + raise SystemExit, 1 + + if options.o: + output = open(options.o, 'wb') + else: + output = sys.stdout + + doit(output, args) + + +def doit(output, dirs): + acc = [] + for d in dirs: + acc.extend(handle_dir(d)) + + uniq = {} + for key, val in acc: + if key in uniq: + if val != uniq[key]: + sys.stderr.write("Duplicate key: %s %s %s\n" % (key, uniq[key], val)) + else: + uniq[key] = val + + t = uniq.items() + t.sort() + write_xyzzy(output, t) + + +def handle_dir(directory): + if not directory.endswith(os.sep): + directory = directory + os.sep + acc = [] + for root, dirs, files in os.walk(directory, topdown=True): + # scm_files = [f for f in files if f.endswith('.scm')] + scm_files = files + for f in scm_files: + full_name = os.path.join(root, f) + t = (full_name[len(directory):], full_name) + acc.append(t) + return acc + + +def file_length(filename): + statinfo = os.stat(filename) + return statinfo.st_size + + +# return n rounded up to a multiple of 4 +def round_up(n): + return (n + 3) & -4 + + +class string_table(object): + def __init__(self): + self._table = '' + self._padding = '\0\0\0\0' + + def add_string(self, s): + r = len(self._table) + len_s = len(s) + padding = self._padding[0:round_up(len_s) - len_s] + self._table = ''.join((self._table, struct.pack('>I', len(s)), s, padding)) + return r + + +def write_xyzzy(f, list_of_tuples): + # tuples: (name, filename) + names = [s[0] for s in list_of_tuples] + number_of_dir_entries = len(list_of_tuples) + number_of_names = number_of_dir_entries + number_of_files = number_of_dir_entries + sizeof_uint32 = 4 + + contents = {} + for name, filename in list_of_tuples: + t = open(filename, 'rb').read() + contents[name] = t + + offset_to_directory = 28 + size_of_directory = number_of_dir_entries * 8 + offset_to_strings = offset_to_directory + size_of_directory + + st = string_table() + + # Insert names in string table first to help locality + name_str_offset = {} + for name in names: + name_str_offset[name] = st.add_string(name) + + # Now add file contents + content_str_offset = {} + for name in names: + content_str_offset[name] = st.add_string(contents[name]) + + size_of_strings = len(st._table) + + if 0: + print "offset_to_directory\t", offset_to_directory + print "size_of_directory\t", size_of_directory + print "number_of_dir_entries\t", number_of_dir_entries + print "offset_to_strings\t", offset_to_strings + print "size_of_strings\t\t", size_of_strings + + magic = '-XyZzY-\0' + + # Write header + f.write(struct.pack('>8s5I', + magic, + offset_to_directory, + size_of_directory, + number_of_dir_entries, + offset_to_strings, + size_of_strings)) + + # Write directory + for name in names: + f.write(struct.pack('>2I', + name_str_offset[name], + content_str_offset[name])) + + # Write string table + f.write(st._table) + + +if __name__ == "__main__": + main() |