1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
#!/usr/bin/env python3
# Copyright (c) 2023 Egor Tensin <egor@tensin.name>
# This file is part of the "cimple" project.
# For details, see https://github.com/egor-tensin/cimple.
# Distributed under the MIT License.
import argparse
from contextlib import contextmanager
from glob import glob
import os
import sys
class Generator:
def __init__(self, fd, dir):
self.fd = fd
if not os.path.isdir(dir):
raise RuntimeError("must be a directory: " + dir)
self.dir = os.path.abspath(dir)
self.name = os.path.basename(self.dir)
def write(self, line):
self.fd.write(f"{line}\n")
def do(self):
self.include_guard_start()
self.include_sql_files()
self.include_guard_end()
def include_guard_start(self):
self.write(f"#ifndef __{self.name.upper()}_SQL_H__")
self.write(f"#define __{self.name.upper()}_SQL_H__")
self.write("")
def include_guard_end(self):
self.write("")
self.write(f"#endif")
def enum_sql_files(self):
return [
os.path.join(self.dir, path)
for path in sorted(glob("*.sql", root_dir=self.dir))
]
@property
def var_name_prefix(self):
return f"{self.name}"
def sql_file_to_var_name(self, path):
name = os.path.splitext(os.path.basename(path))[0]
return f"{self.var_name_prefix}_schema_{name}"
@staticmethod
def sql_file_to_string_literal(path):
with open(path) as fd:
sql = fd.read()
sql = sql.encode().hex().upper()
sql = "".join((f"\\x{sql[i:i + 2]}" for i in range(0, len(sql), 2)))
return sql
def include_sql_files(self):
vars = []
for path in self.enum_sql_files():
name = self.sql_file_to_var_name(path)
vars.append(name)
value = self.sql_file_to_string_literal(path)
self.write(f'static const char *const {name} = "{value}";')
self.write("")
self.write(f"static const char *const {self.var_name_prefix}_schemas[] = {{")
for var in vars:
self.write(f"\t{var},")
self.write("};")
@contextmanager
def open_output(path):
if path is None:
yield sys.stdout
else:
path = os.path.abspath(path)
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as fd:
yield fd
def parse_args(argv=None):
if argv is None:
argv = sys.argv[1:]
parser = argparse.ArgumentParser()
parser.add_argument("-o", "--output", metavar="PATH", help="set output file path")
parser.add_argument("dir", metavar="INPUT_DIR", help="input directory")
return parser.parse_args()
def main(argv=None):
args = parse_args(argv)
with open_output(args.output) as fd:
generator = Generator(fd, args.dir)
generator.do()
if __name__ == "__main__":
main()
|