aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/cmd/tools/vbin2v.v
blob: c1ab6e09dab71c0e1b556435364f6de52efeffbc (plain)
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
module main

import os
import flag
import strings

const (
	tool_version     = '0.0.4'
	tool_description = 'Converts a list of arbitrary files into a single v module file.'
)

struct Context {
mut:
	files       []string
	prefix      string
	show_help   bool
	module_name string
	write_file  string
}

fn (context Context) header() string {
	mut header_s := ''
	header_s += 'module $context.module_name\n'
	header_s += '\n'
	allfiles := context.files.join(' ')
	mut options := []string{}
	if context.prefix.len > 0 {
		options << '-p $context.prefix'
	}
	if context.module_name.len > 0 {
		options << '-m $context.module_name'
	}
	if context.write_file.len > 0 {
		options << '-w $context.write_file'
	}
	soptions := options.join(' ')
	header_s += '// File generated by:\n'
	header_s += '// v bin2v $allfiles $soptions\n'
	header_s += '// Please, do not edit this file.\n'
	header_s += '// Your changes may be overwritten.\n'
	header_s += 'const (\n'
	return header_s
}

fn (context Context) footer() string {
	return ')\n'
}

fn (context Context) file2v(bname string, fbytes []byte, bn_max int) string {
	mut sb := strings.new_builder(1000)
	bn_diff_len := bn_max - bname.len
	sb.write_string('\t${bname}_len' + ' '.repeat(bn_diff_len - 4) + ' = $fbytes.len\n')
	fbyte := fbytes[0]
	bnmae_line := '\t$bname' + ' '.repeat(bn_diff_len) + ' = [byte($fbyte), '
	sb.write_string(bnmae_line)
	mut line_len := bnmae_line.len + 3
	for i := 1; i < fbytes.len; i++ {
		b := int(fbytes[i]).str()
		if line_len > 94 {
			sb.go_back(1)
			sb.write_string('\n\t\t')
			line_len = 8
		}
		if i == fbytes.len - 1 {
			sb.write_string(b)
			line_len += b.len
		} else {
			sb.write_string('$b, ')
			line_len += b.len + 2
		}
	}
	sb.write_string(']!\n')
	return sb.str()
}

fn (context Context) bname_and_bytes(file string) ?(string, []byte) {
	fname := os.file_name(file)
	fname_escaped := fname.replace_each(['.', '_', '-', '_'])
	byte_name := '$context.prefix$fname_escaped'.to_lower()
	fbytes := os.read_bytes(file) or { return error('Error: $err.msg') }
	return byte_name, fbytes
}

fn (context Context) max_bname_len(bnames []string) int {
	mut max := 0
	for n in bnames {
		if n.len > max {
			max = n.len
		}
	}
	// Add 4 to max due to "_len" suffix
	return max + 4
}

fn main() {
	mut context := Context{}
	mut fp := flag.new_flag_parser(os.args[1..])
	fp.application('v bin2v')
	fp.version(tool_version)
	fp.description(tool_description)
	fp.arguments_description('FILE [FILE]...')
	context.show_help = fp.bool('help', `h`, false, 'Show this help screen.')
	context.module_name = fp.string('module', `m`, 'binary', 'Name of the generated module.')
	context.prefix = fp.string('prefix', `p`, '', 'A prefix put before each resource name.')
	context.write_file = fp.string('write', `w`, '', 'Write directly to a file with the given name.')
	if context.show_help {
		println(fp.usage())
		exit(0)
	}
	files := fp.finalize() or {
		eprintln('Error: $err.msg')
		exit(1)
	}
	real_files := files.filter(it != 'bin2v')
	if real_files.len == 0 {
		println(fp.usage())
		exit(0)
	}
	context.files = real_files
	if context.write_file != '' && os.file_ext(context.write_file) !in ['.vv', '.v'] {
		context.write_file += '.v'
	}
	mut file_byte_map := map[string][]byte{}
	for file in real_files {
		bname, fbytes := context.bname_and_bytes(file) or {
			eprintln(err.msg)
			exit(1)
		}
		file_byte_map[bname] = fbytes
	}
	max_bname := context.max_bname_len(file_byte_map.keys())
	if context.write_file.len > 0 {
		mut out_file := os.create(context.write_file) ?
		out_file.write_string(context.header()) ?
		for bname, fbytes in file_byte_map {
			out_file.write_string(context.file2v(bname, fbytes, max_bname)) ?
		}
		out_file.write_string(context.footer()) ?
	} else {
		print(context.header())
		for bname, fbytes in file_byte_map {
			print(context.file2v(bname, fbytes, max_bname))
		}
		print(context.footer())
	}
}