1#!/usr/bin/env python
2#
3# Create frozen modules structure for MicroPython.
4#
5# Usage:
6#
7# Have a directory with modules to be frozen (only modules, not packages
8# supported so far):
9#
10# frozen/foo.py
11# frozen/bar.py
12#
13# Run script, passing path to the directory above:
14#
15# ./make-frozen.py frozen > frozen.c
16#
17# Include frozen.c in your build, having defined MICROPY_MODULE_FROZEN_STR in
18# config.
19#
20from __future__ import print_function
21import sys
22import os
23
24
25def module_name(f):
26    return f
27
28
29modules = []
30
31if len(sys.argv) > 1:
32    root = sys.argv[1].rstrip("/")
33    root_len = len(root)
34
35    for dirpath, dirnames, filenames in os.walk(root):
36        for f in filenames:
37            fullpath = dirpath + "/" + f
38            st = os.stat(fullpath)
39            modules.append((fullpath[root_len + 1 :], st))
40
41print("#include <stdint.h>")
42print("const char mp_frozen_str_names[] = {")
43for f, st in modules:
44    m = module_name(f)
45    print('"%s\\0"' % m)
46print('"\\0"};')
47
48print("const uint32_t mp_frozen_str_sizes[] = {")
49
50for f, st in modules:
51    print("%d," % st.st_size)
52
53print("0};")
54
55print("const char mp_frozen_str_content[] = {")
56for f, st in modules:
57    data = open(sys.argv[1] + "/" + f, "rb").read()
58
59    # We need to properly escape the script data to create a C string.
60    # When C parses hex characters of the form \x00 it keeps parsing the hex
61    # data until it encounters a non-hex character.  Thus one must create
62    # strings of the form "data\x01" "abc" to properly encode this kind of
63    # data.  We could just encode all characters as hex digits but it's nice
64    # to be able to read the resulting C code as ASCII when possible.
65
66    data = bytearray(data)  # so Python2 extracts each byte as an integer
67    esc_dict = {ord("\n"): "\\n", ord("\r"): "\\r", ord('"'): '\\"', ord("\\"): "\\\\"}
68    chrs = ['"']
69    break_str = False
70    for c in data:
71        try:
72            chrs.append(esc_dict[c])
73        except KeyError:
74            if 32 <= c <= 126:
75                if break_str:
76                    chrs.append('" "')
77                    break_str = False
78                chrs.append(chr(c))
79            else:
80                chrs.append("\\x%02x" % c)
81                break_str = True
82    chrs.append('\\0"')
83    print("".join(chrs))
84
85print('"\\0"};')
86