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