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()) } }