1 | module main |
2 | |
3 | import os |
4 | import flag |
5 | import strings |
6 | |
7 | const ( |
8 | tool_version = '0.0.4' |
9 | tool_description = 'Converts a list of arbitrary files into a single v module file.' |
10 | ) |
11 | |
12 | struct Context { |
13 | mut: |
14 | files []string |
15 | prefix string |
16 | show_help bool |
17 | module_name string |
18 | write_file string |
19 | } |
20 | |
21 | fn (context Context) header() string { |
22 | mut header_s := '' |
23 | header_s += 'module ${context.module_name}\n' |
24 | header_s += '\n' |
25 | allfiles := context.files.join(' ') |
26 | mut options := []string{} |
27 | if context.prefix.len > 0 { |
28 | options << '-p ${context.prefix}' |
29 | } |
30 | if context.module_name.len > 0 { |
31 | options << '-m ${context.module_name}' |
32 | } |
33 | if context.write_file.len > 0 { |
34 | options << '-w ${context.write_file}' |
35 | } |
36 | soptions := options.join(' ') |
37 | header_s += '// File generated by:\n' |
38 | header_s += '// v bin2v ${allfiles} ${soptions}\n' |
39 | header_s += '// Please, do not edit this file.\n' |
40 | header_s += '// Your changes may be overwritten.\n' |
41 | header_s += 'const (\n' |
42 | return header_s |
43 | } |
44 | |
45 | fn (context Context) footer() string { |
46 | return ')\n' |
47 | } |
48 | |
49 | fn (context Context) file2v(bname string, fbytes []u8, bn_max int) string { |
50 | mut sb := strings.new_builder(1000) |
51 | bn_diff_len := bn_max - bname.len |
52 | sb.write_string('\t${bname}_len' + ' '.repeat(bn_diff_len - 4) + ' = ${fbytes.len}\n') |
53 | fbyte := fbytes[0] |
54 | bnmae_line := '\t${bname}' + ' '.repeat(bn_diff_len) + ' = [u8(${fbyte}), ' |
55 | sb.write_string(bnmae_line) |
56 | mut line_len := bnmae_line.len + 3 |
57 | for i := 1; i < fbytes.len; i++ { |
58 | b := int(fbytes[i]).str() |
59 | if line_len > 94 { |
60 | sb.go_back(1) |
61 | sb.write_string('\n\t\t') |
62 | line_len = 8 |
63 | } |
64 | if i == fbytes.len - 1 { |
65 | sb.write_string(b) |
66 | line_len += b.len |
67 | } else { |
68 | sb.write_string('${b}, ') |
69 | line_len += b.len + 2 |
70 | } |
71 | } |
72 | sb.write_string(']!\n') |
73 | return sb.str() |
74 | } |
75 | |
76 | fn (context Context) bname_and_bytes(file string) !(string, []u8) { |
77 | fname := os.file_name(file) |
78 | fname_escaped := fname.replace_each(['.', '_', '-', '_']) |
79 | byte_name := '${context.prefix}${fname_escaped}'.to_lower() |
80 | fbytes := os.read_bytes(file) or { return error('Error: ${err.msg()}') } |
81 | return byte_name, fbytes |
82 | } |
83 | |
84 | fn (context Context) max_bname_len(bnames []string) int { |
85 | mut max := 0 |
86 | for n in bnames { |
87 | if n.len > max { |
88 | max = n.len |
89 | } |
90 | } |
91 | // Add 4 to max due to "_len" suffix |
92 | return max + 4 |
93 | } |
94 | |
95 | fn main() { |
96 | mut context := Context{} |
97 | mut fp := flag.new_flag_parser(os.args[1..]) |
98 | fp.application('v bin2v') |
99 | fp.version(tool_version) |
100 | fp.description(tool_description) |
101 | fp.arguments_description('FILE [FILE]...') |
102 | context.show_help = fp.bool('help', `h`, false, 'Show this help screen.') |
103 | context.module_name = fp.string('module', `m`, 'binary', 'Name of the generated module.') |
104 | context.prefix = fp.string('prefix', `p`, '', 'A prefix put before each resource name.') |
105 | context.write_file = fp.string('write', `w`, '', 'Write directly to a file with the given name.') |
106 | if context.show_help { |
107 | println(fp.usage()) |
108 | exit(0) |
109 | } |
110 | files := fp.finalize() or { |
111 | eprintln('Error: ${err.msg()}') |
112 | exit(1) |
113 | } |
114 | real_files := files.filter(it != 'bin2v') |
115 | if real_files.len == 0 { |
116 | println(fp.usage()) |
117 | exit(0) |
118 | } |
119 | context.files = real_files |
120 | if context.write_file != '' && os.file_ext(context.write_file) !in ['.vv', '.v'] { |
121 | context.write_file += '.v' |
122 | } |
123 | mut file_byte_map := map[string][]u8{} |
124 | for file in real_files { |
125 | bname, fbytes := context.bname_and_bytes(file) or { |
126 | eprintln(err.msg()) |
127 | exit(1) |
128 | } |
129 | file_byte_map[bname] = fbytes |
130 | } |
131 | max_bname := context.max_bname_len(file_byte_map.keys()) |
132 | if context.write_file.len > 0 { |
133 | mut out_file := os.create(context.write_file)! |
134 | out_file.write_string(context.header())! |
135 | for bname, fbytes in file_byte_map { |
136 | out_file.write_string(context.file2v(bname, fbytes, max_bname))! |
137 | } |
138 | out_file.write_string(context.footer())! |
139 | } else { |
140 | print(context.header()) |
141 | for bname, fbytes in file_byte_map { |
142 | print(context.file2v(bname, fbytes, max_bname)) |
143 | } |
144 | print(context.footer()) |
145 | } |
146 | } |