odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

main.odin (5299B)


      1 package bindgen2
      2 
      3 import vmem "core:mem/virtual"
      4 import "core:mem"
      5 import "core:os"
      6 import "core:os/os2"
      7 import "core:fmt"
      8 import "core:strings"
      9 import "core:path/filepath"
     10 import "base:runtime"
     11 import "core:encoding/json"
     12 import "core:slice"
     13 import "core:log"
     14 
     15 main :: proc() {
     16 	permanent_arena: vmem.Arena
     17 	permanent_allocator := vmem.arena_allocator(&permanent_arena)
     18 	context.allocator = permanent_allocator
     19 	context.temp_allocator = permanent_allocator
     20 	context.logger = log.create_console_logger()
     21 
     22 	ensure(len(os.args) == 2, "Usage: 'bindgen directory' or 'bindgen directory/bindgen.sjson'")
     23 	config_dir_or_file := os.args[1]
     24 
     25 	DEFAULT_CONFIG_FILENAME :: "bindgen.sjson"
     26 	
     27 	config_filename: string
     28 	dir: string
     29 
     30 	if strings.has_suffix(config_dir_or_file, ".sjson") && os.is_file(config_dir_or_file) {
     31 		config_filename = config_dir_or_file
     32 		dir = filepath.dir(config_dir_or_file)
     33 	} else if os.is_dir(config_dir_or_file) {
     34 		config_filename = filepath.join({config_dir_or_file, DEFAULT_CONFIG_FILENAME})
     35 		dir = config_dir_or_file
     36 	} else {
     37 		fmt.panicf("%v is not a directory nor a valid config file", config_dir_or_file)
     38 	}
     39 
     40 	default_output_folder := "output"
     41 	default_package_name := "pkg"
     42 
     43 	if config_dir_handle, config_dir_handle_err := os2.open(dir); config_dir_handle_err == nil {
     44 		if stat, stat_err := config_dir_handle.fstat(config_dir_handle, context.allocator); stat_err == nil {
     45 			default_output_folder = stat.name
     46 			default_package_name = stat.name
     47 		}
     48 	}
     49 
     50 	config: Config
     51 
     52 	if os.is_file(config_filename) {
     53 		if config_data, config_data_ok := os.read_entire_file(config_filename); config_data_ok {
     54 			config_err := json.unmarshal(config_data, &config, .SJSON)
     55 			fmt.ensuref(
     56 				config_err == nil,
     57 				"Failed parsing config %v: %v",
     58 				config_filename,
     59 				config_err,
     60 			)
     61 		} else {
     62 			fmt.ensuref(config_data_ok, "Failed parsing config %v", config_filename)
     63 		}
     64 	} else {
     65 		config.inputs = slice.clone([]string{"."})
     66 	}
     67 
     68 	output_folder := filepath.join({dir, config.output_folder != "" ? config.output_folder : default_output_folder})
     69 	package_name := config.package_name != "" ? config.package_name : default_package_name
     70 	
     71 	if config.imports_file != "" {
     72 		config.imports_file = filepath.join({dir, config.imports_file})
     73 	}
     74 
     75 	input_files: [dynamic]string
     76 
     77 	for input_base in config.inputs {
     78 		input := filepath.join({dir, input_base})
     79 		if os.is_dir(input) {
     80 			input_folder, input_folder_err := os2.open(input)
     81 			log.ensuref(input_folder_err == nil, "Failed opening folder %v: %v", input, input_folder_err)
     82 			iter := os2.read_directory_iterator_create(input_folder)
     83 
     84 			for f in os2.read_directory_iterator(&iter) {
     85 				if f.type != .Regular {
     86 					continue
     87 				}
     88 
     89 				append(&input_files, filepath.join({input, f.name}))
     90 			}
     91 
     92 			os2.close(input_folder)
     93 		} else if os.is_file(input) {
     94 			append(&input_files, input)
     95 		} else {
     96 			log.errorf("%v is neither directory or .h file", input)
     97 		}
     98 	}
     99 
    100 	if output_folder != "" && !os2.exists(output_folder) {
    101 		make_dir_err := os2.make_directory_all(output_folder)
    102 		log.ensuref(make_dir_err == nil, "Failed creating output directory %v: %v", output_folder, make_dir_err)
    103 	}
    104 
    105 	for input_filename in input_files {
    106 		if filepath.ext(input_filename) == ".h" {
    107 			types_arena: vmem.Arena
    108 			types_arena_err := vmem.arena_init_static(&types_arena, 100 * mem.Megabyte)
    109 			log.assertf(types_arena_err == nil, "Failed reserving types arena memory. Error: %v", types_arena_err)
    110 
    111 			decls_arena: vmem.Arena
    112 			decls_arena_err := vmem.arena_init_static(&decls_arena, 100 * mem.Megabyte)
    113 			log.assertf(decls_arena_err == nil, "Failed reserving types arena memory. Error: %v", decls_arena_err)
    114 
    115 			type_arr := make([dynamic]Type, allocator = vmem.arena_allocator(&types_arena))
    116 			types := Type_List(&type_arr)
    117 			decl_arr := make([dynamic]Decl, allocator = vmem.arena_allocator(&decls_arena))
    118 			decls := Decl_List(&decl_arr)
    119 
    120 			add_decl(decls, {})
    121 			add_type(types, {})
    122 
    123 			gen_arena: vmem.Arena
    124 			context.allocator = vmem.arena_allocator(&gen_arena)
    125 			context.temp_allocator = vmem.arena_allocator(&gen_arena)
    126 			gen_ctx = context
    127 			
    128 			log.infof("Collecting data from %v", input_filename)
    129 			collect_res, collect_ok := translate_collect(input_filename, config, types, decls)
    130 
    131 			if !collect_ok {
    132 				continue
    133 			}
    134 
    135 			translate_macros(collect_res.macros, decls)
    136 
    137 			log.infof("Processing data from %v", input_filename)
    138 			process_res := translate_process(collect_res, config, types, decls)
    139 	
    140 			input_folder := filepath.dir(input_filename)
    141 			filename_stem := filepath.stem(input_filename)
    142 			footer_filename := filepath.join({input_folder, fmt.tprintf("%v_footer.odin", filename_stem)})
    143 
    144 			footer: string
    145 			if os.exists(footer_filename) {
    146 				if footer_bytes, footer_bytes_ok := os.read_entire_file(footer_filename); footer_bytes_ok {
    147 					footer = string(footer_bytes)
    148 				}
    149 			}
    150 
    151 			output_filename := filepath.join({output_folder, fmt.tprintf("%v.odin", filename_stem)})
    152 			log.infof("Writing %v", output_filename)
    153 			output(types, decls, process_res, output_filename, footer, package_name)
    154 			vmem.arena_destroy(&gen_arena)
    155 			vmem.arena_destroy(&types_arena)
    156 			vmem.arena_destroy(&decls_arena)
    157 		}
    158 	}
    159 }
    160 
    161 gen_ctx: runtime.Context
    162 
    163 to_cstring :: proc(str: string) -> cstring {
    164 	return strings.clone_to_cstring(str)
    165 }