# HG changeset patch # User Michael Pavone # Date 1492842932 25200 # Node ID 071e761bcdcfa95bf422da94f35adaef3ab9979a # Parent 58bfbed6cdb500b565cbe3398ef4cbecec4e4df6 Fix a deficiency in the way types were handled in my ternary tree. Fixes in which some paths that were constructed from a template with variables would sometimes get an extra garbage character thrown in diff -r 58bfbed6cdb5 -r 071e761bcdcf blastem.c --- a/blastem.c Fri Apr 21 01:22:52 2017 -0700 +++ b/blastem.c Fri Apr 21 23:35:32 2017 -0700 @@ -140,7 +140,7 @@ void setup_saves(char *fname, rom_info *info, system_header *context) { static uint8_t persist_save_registered; - char *savedir_template = tern_find_path(config, "ui\0save_path\0").ptrval; + char *savedir_template = tern_find_path(config, "ui\0save_path\0", TVAL_PTR).ptrval; if (!savedir_template) { savedir_template = "$USERDATA/blastem/$ROMNAME"; } @@ -322,7 +322,7 @@ uint8_t menu = !loaded; if (!loaded) { //load menu - romfname = tern_find_path(config, "ui\0rom\0").ptrval; + romfname = tern_find_path(config, "ui\0rom\0", TVAL_PTR).ptrval; if (!romfname) { romfname = "menu.bin"; } @@ -349,7 +349,7 @@ } int def_width = 0; - char *config_width = tern_find_path(config, "video\0width\0").ptrval; + char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval; if (config_width) { def_width = atoi(config_width); } @@ -359,7 +359,7 @@ width = width < 320 ? def_width : width; height = height < 240 ? (width/320) * 240 : height; - char *config_fullscreen = tern_find_path(config, "video\0fullscreen\0").ptrval; + char *config_fullscreen = tern_find_path(config, "video\0fullscreen\0", TVAL_PTR).ptrval; if (config_fullscreen && !strcmp("on", config_fullscreen)) { fullscreen = !fullscreen; } diff -r 58bfbed6cdb5 -r 071e761bcdcf genesis.c --- a/genesis.c Fri Apr 21 01:22:52 2017 -0700 +++ b/genesis.c Fri Apr 21 23:35:32 2017 -0700 @@ -822,7 +822,7 @@ void set_region(genesis_context *gen, rom_info *info, uint8_t region) { if (!region) { - char * def_region = tern_find_path_default(config, "system\0default_region\0", (tern_val){.ptrval = "U"}).ptrval; + char * def_region = tern_find_path_default(config, "system\0default_region\0", (tern_val){.ptrval = "U"}, TVAL_PTR).ptrval; if (!info->regions || (info->regions & translate_region_char(toupper(*def_region)))) { region = translate_region_char(toupper(*def_region)); } else { @@ -1001,10 +1001,10 @@ init_vdp_context(gen->vdp, gen->version_reg & 0x40); gen->vdp->system = &gen->header; gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); - char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval; + char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval; gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; - char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0").ptrval; + char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF; gen->ym = malloc(sizeof(ym2612_context)); @@ -1032,7 +1032,7 @@ gen->cart = main_rom; gen->lock_on = lock_on; gen->work_ram = calloc(2, RAM_WORDS); - if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}).ptrval)) + if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) { srand(time(NULL)); for (int i = 0; i < RAM_WORDS; i++) @@ -1124,7 +1124,7 @@ byteswap_rom(lock_on_size, lock_on); } #endif - char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0").ptrval; + char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval; if (!m68k_divider) { m68k_divider = "7"; } diff -r 58bfbed6cdb5 -r 071e761bcdcf io.c --- a/io.c Fri Apr 21 01:22:52 2017 -0700 +++ b/io.c Fri Apr 21 23:35:32 2017 -0700 @@ -494,7 +494,7 @@ current_system->soft_reset(current_system); break; case UI_SCREENSHOT: { - char *screenshot_base = tern_find_path(config, "ui\0screenshot_path\0").ptrval; + char *screenshot_base = tern_find_path(config, "ui\0screenshot_path\0", TVAL_PTR).ptrval; if (!screenshot_base) { screenshot_base = "$HOME"; } @@ -505,7 +505,7 @@ time_t now = time(NULL); struct tm local_store; char fname_part[256]; - char *template = tern_find_path(config, "ui\0screenshot_template\0").ptrval; + char *template = tern_find_path(config, "ui\0screenshot_template\0", TVAL_PTR).ptrval; if (!template) { template = "blastem_%c.ppm"; } @@ -876,10 +876,10 @@ { current_io = io; io_port * ports = current_io->ports; - tern_node *io_nodes = tern_get_node(tern_find_path(config, "io\0devices\0")); - char * io_1 = rom->port1_override ? rom->port1_override : tern_find_ptr(io_nodes, "1"); - char * io_2 = rom->port2_override ? rom->port2_override : tern_find_ptr(io_nodes, "2"); - char * io_ext = rom->ext_override ? rom->ext_override : tern_find_ptr(io_nodes, "ext"); + tern_node *io_nodes = tern_find_path(config, "io\0devices\0", TVAL_NODE).ptrval; + char * io_1 = rom->port1_override ? rom->port1_override : io_nodes ? tern_find_ptr(io_nodes, "1") : NULL; + char * io_2 = rom->port2_override ? rom->port2_override : io_nodes ? tern_find_ptr(io_nodes, "2") : NULL; + char * io_ext = rom->ext_override ? rom->ext_override : io_nodes ? tern_find_ptr(io_nodes, "ext") : NULL; process_device(io_1, ports); process_device(io_2, ports+1); @@ -901,7 +901,7 @@ #ifndef _WIN32 if (ports[i].device_type == IO_SEGA_PARALLEL) { - char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0").ptrval; + char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0", TVAL_PTR).ptrval; if (!pipe_name) { warning("IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i)); @@ -927,7 +927,7 @@ } } } else if (ports[i].device_type == IO_GENERIC) { - char *sock_name = tern_find_path(config, "io\0socket\0").ptrval; + char *sock_name = tern_find_path(config, "io\0socket\0", TVAL_PTR).ptrval; if (!sock_name) { warning("IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); @@ -1013,7 +1013,7 @@ int mouseidx; } pmb_state; -void process_mouse_button(char *buttonstr, tern_val value, void *data) +void process_mouse_button(char *buttonstr, tern_val value, uint8_t valtype, void *data) { pmb_state *state = data; int buttonnum = atoi(buttonstr); @@ -1021,6 +1021,10 @@ warning("Mouse button %s is out of the supported range of 1-8\n", buttonstr); return; } + if (valtype != TVAL_PTR) { + warning("Mouse button %s is not a scalar value!\n", buttonstr); + return; + } buttonnum--; int ui_func, devicenum, button; int bindtype = parse_binding_target(value.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &devicenum, &button); @@ -1045,17 +1049,17 @@ } -void process_mouse(char *mousenum, tern_val value, void *data) +void process_mouse(char *mousenum, tern_val value, uint8_t valtype, void *data) { tern_node **buttonmaps = data; - tern_node *mousedef = tern_get_node(value); + if (valtype != TVAL_NODE) { + warning("Binding for mouse %s is a scalar!\n", mousenum); + return; + } + tern_node *mousedef = value.ptrval; tern_node *padbuttons = buttonmaps[0]; tern_node *mousebuttons = buttonmaps[1]; - if (!mousedef) { - warning("Binding for mouse %s is a scalar!\n", mousenum); - return; - } int mouseidx = atoi(mousenum); if (mouseidx < 0 || mouseidx >= MAX_MICE) { warning("Mouse numbers must be between 0 and %d, but %d is not\n", MAX_MICE, mouseidx); @@ -1074,7 +1078,7 @@ warning("Mouse motion can't be bound to target %s\n", motion); } } - tern_node *buttons = tern_get_node(tern_find_path(mousedef, "buttons\0\0")); + tern_node *buttons = tern_find_path(mousedef, "buttons\0\0", TVAL_NODE).ptrval; if (buttons) { pmb_state state = {padbuttons, mousebuttons, mouseidx}; tern_foreach(buttons, process_mouse_button, &state); @@ -1087,11 +1091,15 @@ tern_node *mousebuttons; } pad_button_state; -void process_pad_button(char *key, tern_val val, void *data) +void process_pad_button(char *key, tern_val val, uint8_t valtype, void *data) { pad_button_state *state = data; int hostpadnum = state->padnum; int ui_func, padnum, button; + if (valtype != TVAL_PTR) { + warning("Pad button %s has a non-scalar value\n", key); + return; + } int bindtype = parse_binding_target(val.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &padnum, &button); char *end; long hostbutton = strtol(key, &end, 10); @@ -1129,12 +1137,16 @@ } } -void process_pad_axis(char *key, tern_val val, void *data) +void process_pad_axis(char *key, tern_val val, uint8_t valtype, void *data) { key = strdup(key); pad_button_state *state = data; int hostpadnum = state->padnum; int ui_func, padnum, button; + if (valtype != TVAL_PTR) { + warning("Mapping for axis %s has a non-scalar value", key); + return; + } int bindtype = parse_binding_target(val.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &padnum, &button); char *modifier = strchr(key, '.'); int positive = 1; @@ -1226,19 +1238,19 @@ if (joystick > MAX_JOYSTICKS) { return; } - tern_node * pads = tern_get_node(tern_find_path(config, "bindings\0pads\0")); + tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval; if (pads) { char numstr[11]; sprintf(numstr, "%d", joystick); - tern_node * pad = tern_find_ptr(pads, numstr); + tern_node * pad = tern_find_node(pads, numstr); if (pad) { - tern_node * dpad_node = tern_find_ptr(pad, "dpads"); + tern_node * dpad_node = tern_find_node(pad, "dpads"); if (dpad_node) { for (int dpad = 0; dpad < 10; dpad++) { numstr[0] = dpad + '0'; numstr[1] = 0; - tern_node * pad_dpad = tern_find_ptr(dpad_node, numstr); + tern_node * pad_dpad = tern_find_node(dpad_node, numstr); char * dirs[] = {"up", "down", "left", "right"}; int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { @@ -1255,7 +1267,7 @@ } } } - tern_node *button_node = tern_find_ptr(pad, "buttons"); + tern_node *button_node = tern_find_node(pad, "buttons"); if (button_node) { pad_button_state state = { .padnum = joystick, @@ -1264,7 +1276,7 @@ }; tern_foreach(button_node, process_pad_button, &state); } - tern_node *axes_node = tern_find_ptr(pad, "axes"); + tern_node *axes_node = tern_find_node(pad, "axes"); if (axes_node) { pad_button_state state = { .padnum = joystick, @@ -1347,10 +1359,10 @@ tern_node *mousebuttons = get_mouse_buttons(); - tern_node * keys = tern_get_node(tern_find_path(config, "bindings\0keys\0")); + tern_node * keys = tern_find_path(config, "bindings\0keys\0", TVAL_NODE).ptrval; process_keys(keys, special, padbuttons, mousebuttons, NULL); char numstr[] = "00"; - tern_node * pads = tern_get_node(tern_find_path(config, "bindings\0pads\0")); + tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval; if (pads) { for (int i = 0; i < MAX_JOYSTICKS; i++) { @@ -1366,12 +1378,12 @@ } } memset(mice, 0, sizeof(mice)); - tern_node * mice = tern_get_node(tern_find_path(config, "bindings\0mice\0")); + tern_node * mice = tern_find_path(config, "bindings\0mice\0", TVAL_NODE).ptrval; if (mice) { tern_node *buttonmaps[2] = {padbuttons, mousebuttons}; tern_foreach(mice, process_mouse, buttonmaps); } - tern_node * speed_nodes = tern_get_node(tern_find_path(config, "clocks\0speeds\0")); + tern_node * speed_nodes = tern_find_path(config, "clocks\0speeds\0", TVAL_NODE).ptrval; speeds = malloc(sizeof(uint32_t)); speeds[0] = 100; process_speeds(speed_nodes, NULL); diff -r 58bfbed6cdb5 -r 071e761bcdcf menu.c --- a/menu.c Fri Apr 21 01:22:52 2017 -0700 +++ b/menu.c Fri Apr 21 23:35:32 2017 -0700 @@ -166,7 +166,7 @@ menu_context *menu = gen->extra; if (!menu) { gen->extra = menu = calloc(1, sizeof(menu_context)); - menu->curpath = tern_find_path(config, "ui\0initial_path\0").ptrval; + menu->curpath = tern_find_path(config, "ui\0initial_path\0", TVAL_PTR).ptrval; if (!menu->curpath){ #ifdef __ANDROID__ menu->curpath = get_external_storage_path(); diff -r 58bfbed6cdb5 -r 071e761bcdcf render_sdl.c --- a/render_sdl.c Fri Apr 21 01:22:52 2017 -0700 +++ b/render_sdl.c Fri Apr 21 23:35:32 2017 -0700 @@ -217,9 +217,9 @@ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); tern_val def = {.ptrval = "default.v.glsl"}; - vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); + vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def, TVAL_PTR).ptrval, GL_VERTEX_SHADER); def.ptrval = "default.f.glsl"; - fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER); + fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def, TVAL_PTR).ptrval, GL_FRAGMENT_SHADER); program = glCreateProgram(); glAttachShader(program, vshader); glAttachShader(program, fshader); @@ -284,7 +284,7 @@ main_clip.h = main_height; main_clip.x = main_clip.y = 0; //calculate configured aspect ratio - char *config_aspect = tern_find_path_default(config, "video\0aspect\0", (tern_val){.ptrval = "4:3"}).ptrval; + char *config_aspect = tern_find_path_default(config, "video\0aspect\0", (tern_val){.ptrval = "4:3"}, TVAL_PTR).ptrval; if (strcmp("stretch", config_aspect)) { float src_aspect = 4.0f/3.0f; char *end; @@ -356,32 +356,28 @@ render_gl = 0; tern_val def = {.ptrval = "off"}; - char *vsync = tern_find_path_default(config, "video\0vsync\0", def).ptrval; + char *vsync = tern_find_path_default(config, "video\0vsync\0", def, TVAL_PTR).ptrval; - tern_val video_node = {.ptrval = NULL}; - tern_find(config, "video", &video_node); - tern_node *video = tern_get_node(video_node); + tern_node *video = tern_find_node(config, "video"); if (video) { for (int i = 0; i < NUM_VID_STD; i++) { - video_node.ptrval = NULL; - tern_find(video, vid_std_names[i], &video_node); - tern_node *std_settings = tern_get_node(video_node); + tern_node *std_settings = tern_find_node(video, vid_std_names[i]); if (std_settings) { - char *val = tern_find_path_default(std_settings, "overscan\0top\0", (tern_val){.ptrval = NULL}).ptrval; + char *val = tern_find_path_default(std_settings, "overscan\0top\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval; if (val) { overscan_top[i] = atoi(val); } - val = tern_find_path_default(std_settings, "overscan\0bottom\0", (tern_val){.ptrval = NULL}).ptrval; + val = tern_find_path_default(std_settings, "overscan\0bottom\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval; if (val) { overscan_bot[i] = atoi(val); } - val = tern_find_path_default(std_settings, "overscan\0left\0", (tern_val){.ptrval = NULL}).ptrval; + val = tern_find_path_default(std_settings, "overscan\0left\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval; if (val) { overscan_left[i] = atoi(val); } - val = tern_find_path_default(std_settings, "overscan\0right\0", (tern_val){.ptrval = NULL}).ptrval; + val = tern_find_path_default(std_settings, "overscan\0right\0", (tern_val){.ptrval = NULL}, TVAL_PTR).ptrval; if (val) { overscan_right[i] = atoi(val); } @@ -447,7 +443,7 @@ update_aspect(); render_alloc_surfaces(); def.ptrval = "off"; - scanlines = !strcmp(tern_find_path_default(config, "video\0scanlines\0", def).ptrval, "on"); + scanlines = !strcmp(tern_find_path_default(config, "video\0scanlines\0", def, TVAL_PTR).ptrval, "on"); caption = title; @@ -457,7 +453,7 @@ audio_ready = SDL_CreateCond(); SDL_AudioSpec desired, actual; - char * rate_str = tern_find_path(config, "audio\0rate\0").ptrval; + char * rate_str = tern_find_path(config, "audio\0rate\0", TVAL_PTR).ptrval; int rate = rate_str ? atoi(rate_str) : 0; if (!rate) { rate = 48000; @@ -465,7 +461,7 @@ desired.freq = rate; desired.format = AUDIO_S16SYS; desired.channels = 2; - char * samples_str = tern_find_path(config, "audio\0buffer\0").ptrval; + char * samples_str = tern_find_path(config, "audio\0buffer\0", TVAL_PTR).ptrval; int samples = samples_str ? atoi(samples_str) : 0; if (!samples) { samples = 512; diff -r 58bfbed6cdb5 -r 071e761bcdcf romdb.c --- a/romdb.c Fri Apr 21 01:22:52 2017 -0700 +++ b/romdb.c Fri Apr 21 23:35:32 2017 -0700 @@ -643,13 +643,17 @@ uint16_t ptr_index; } map_iter_state; -void eeprom_read_fun(char *key, tern_val val, void *data) +void eeprom_read_fun(char *key, tern_val val, uint8_t valtype, void *data) { int bit = atoi(key); if (bit < 0 || bit > 15) { fprintf(stderr, "bit %s is out of range", key); return; } + if (valtype != TVAL_PTR) { + fprintf(stderr, "bit %s has a non-scalar value", key); + return; + } char *pin = val.ptrval; if (strcmp(pin, "sda")) { fprintf(stderr, "bit %s is connected to unrecognized read pin %s", key, pin); @@ -659,13 +663,17 @@ map->sda_read_bit = bit; } -void eeprom_write_fun(char *key, tern_val val, void *data) +void eeprom_write_fun(char *key, tern_val val, uint8_t valtype, void *data) { int bit = atoi(key); if (bit < 0 || bit > 15) { fprintf(stderr, "bit %s is out of range", key); return; } + if (valtype != TVAL_PTR) { + fprintf(stderr, "bit %s has a non-scalar value", key); + return; + } char *pin = val.ptrval; eeprom_map *map = data; if (!strcmp(pin, "sda")) { @@ -682,7 +690,7 @@ void process_sram_def(char *key, map_iter_state *state) { if (!state->info->save_size) { - char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; + char * size = tern_find_path(state->root, "SRAM\0size\0", TVAL_PTR).ptrval; if (!size) { fatal_error("ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); } @@ -693,7 +701,7 @@ state->info->save_mask = nearest_pow2(state->info->save_size)-1; state->info->save_buffer = malloc(state->info->save_size); memset(state->info->save_buffer, 0, state->info->save_size); - char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; + char *bus = tern_find_path(state->root, "SRAM\0bus\0", TVAL_PTR).ptrval; if (!strcmp(bus, "odd")) { state->info->save_type = RAM_FLAG_ODD; } else if(!strcmp(bus, "even")) { @@ -707,7 +715,7 @@ void process_eeprom_def(char * key, map_iter_state *state) { if (!state->info->save_size) { - char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval; + char * size = tern_find_path(state->root, "EEPROM\0size\0", TVAL_PTR).ptrval; if (!size) { fatal_error("ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key); } @@ -715,7 +723,7 @@ if (!state->info->save_size) { fatal_error("EEPROM size %s is invalid\n", size); } - char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval; + char *etype = tern_find_path(state->root, "EEPROM\0type\0", TVAL_PTR).ptrval; if (!etype) { etype = "i2c"; } @@ -737,11 +745,11 @@ eep_map->start = start; eep_map->end = end; eep_map->sda_read_bit = 0xFF; - tern_node * bits_read = tern_find_ptr(node, "bits_read"); + tern_node * bits_read = tern_find_node(node, "bits_read"); if (bits_read) { tern_foreach(bits_read, eeprom_read_fun, eep_map); } - tern_node * bits_write = tern_find_ptr(node, "bits_write"); + tern_node * bits_write = tern_find_node(node, "bits_write"); if (bits_write) { tern_foreach(bits_write, eeprom_write_fun, eep_map); } @@ -749,13 +757,13 @@ state->info->num_eeprom++; } -void map_iter_fun(char *key, tern_val val, void *data) +void map_iter_fun(char *key, tern_val val, uint8_t valtype, void *data) { map_iter_state *state = data; - tern_node *node = tern_get_node(val); - if (!node) { + if (valtype != TVAL_NODE) { fatal_error("ROM DB map entry %d with address %s is not a node\n", state->index, key); } + tern_node *node = val.ptrval; uint32_t start = strtol(key, NULL, 16); uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16); if (!end || end < start) { @@ -819,7 +827,7 @@ state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7); map = state->info->map + state->index; - char *save_device = tern_find_path(node, "save\0device\0").ptrval; + char *save_device = tern_find_path(node, "save\0device\0", TVAL_PTR).ptrval; if (save_device && !strcmp(save_device, "EEPROM")) { process_eeprom_def(key, state); add_eeprom_map(node, start & map->mask, end & map->mask, state); @@ -892,9 +900,9 @@ uint8_t hex_hash[41]; bin_to_hex(hex_hash, raw_hash, 20); printf("SHA1: %s\n", hex_hash); - tern_node * entry = tern_find_ptr(rom_db, hex_hash); + tern_node * entry = tern_find_node(rom_db, hex_hash); if (!entry) { - entry = tern_find_ptr(rom_db, product_id); + entry = tern_find_node(rom_db, product_id); } if (!entry) { puts("Not found in ROM DB, examining header\n"); @@ -927,7 +935,7 @@ info.regions = get_header_regions(rom); } - tern_node *map = tern_find_ptr(entry, "map"); + tern_node *map = tern_find_node(entry, "map"); if (map) { info.save_type = SAVE_NONE; info.map_chunks = tern_count(map); @@ -959,7 +967,7 @@ add_memmap_header(&info, rom, rom_size, base_map, base_chunks); } - tern_node *device_overrides = tern_find_ptr(entry, "device_overrides"); + tern_node *device_overrides = tern_find_node(entry, "device_overrides"); if (device_overrides) { info.port1_override = tern_find_ptr(device_overrides, "1"); info.port2_override = tern_find_ptr(device_overrides, "2"); diff -r 58bfbed6cdb5 -r 071e761bcdcf sms.c --- a/sms.c Fri Apr 21 01:22:52 2017 -0700 +++ b/sms.c Fri Apr 21 23:35:32 2017 -0700 @@ -324,7 +324,7 @@ sms->bank_regs[3] = 0x8000 >> 14; } - char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0").ptrval; + char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : 3390; //TODO: Detect region and pick master clock based off of that diff -r 58bfbed6cdb5 -r 071e761bcdcf tern.c --- a/tern.c Fri Apr 21 01:22:52 2017 -0700 +++ b/tern.c Fri Apr 21 23:35:32 2017 -0700 @@ -10,7 +10,7 @@ #include #include "util.h" -tern_node * tern_insert(tern_node * head, char const * key, tern_val value) +tern_node * tern_insert(tern_node * head, char const * key, tern_val value, uint8_t valtype) { tern_node ** cur = &head; while(*key) @@ -31,6 +31,7 @@ (*cur)->right = NULL; (*cur)->straight.next = NULL; (*cur)->el = *key; + (*cur)->valtype = TVAL_NONE; } cur = &((*cur)->straight.next); key++; @@ -46,10 +47,11 @@ (*cur)->el = 0; } (*cur)->straight.value = value; + (*cur)->valtype = valtype; return head; } -int tern_find(tern_node * head, char const * key, tern_val *ret) +uint8_t tern_find(tern_node * head, char const * key, tern_val *ret) { tern_node * cur = head; while (cur) @@ -60,7 +62,7 @@ key++; } else { *ret = cur->straight.value; - return 1; + return cur->valtype; } } else if (*key < cur->el) { cur = cur->left; @@ -68,7 +70,7 @@ cur = cur->right; } } - return 0; + return TVAL_NONE; } tern_node * tern_find_prefix(tern_node * head, char const * key) @@ -91,7 +93,8 @@ intptr_t tern_find_int(tern_node * head, char const * key, intptr_t def) { tern_val ret; - if (tern_find(head, key, &ret)) { + uint8_t valtype = tern_find(head, key, &ret); + if (valtype == TVAL_INT) { return ret.intval; } return def; @@ -101,18 +104,15 @@ { tern_val val; val.intval = value; - return tern_insert(head, key, val); + return tern_insert(head, key, val, TVAL_INT); } void * tern_find_ptr_default(tern_node * head, char const * key, void * def) { tern_val ret; - if (tern_find(head, key, &ret)) { - if (ret.intval & 1) { - return (void *)(ret.intval & ~1); - } else { - return ret.ptrval; - } + uint8_t valtype = tern_find(head, key, &ret); + if (valtype == TVAL_PTR) { + return ret.ptrval; } return def; } @@ -122,44 +122,57 @@ return tern_find_ptr_default(head, key, NULL); } -tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def) +tern_node *tern_find_node(tern_node *head, char const *key) +{ + tern_val ret; + uint8_t valtype = tern_find(head, key, &ret); + if (valtype == TVAL_NODE) { + return ret.ptrval; + } + return NULL; +} + +tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def, uint8_t req_valtype) { tern_val ret; while (*key) { - if (!tern_find(head, key, &ret)) { + uint8_t valtype = tern_find(head, key, &ret); + if (!valtype) { return def; } key = key + strlen(key) + 1; if (*key) { - head = tern_get_node(ret); - if (!head) { + if (valtype != TVAL_NODE) { return def; } + head = ret.ptrval; + } else if (req_valtype && req_valtype != valtype) { + return def; } } return ret; } -tern_val tern_find_path(tern_node *head, char const *key) +tern_val tern_find_path(tern_node *head, char const *key, uint8_t valtype) { tern_val def; def.ptrval = NULL; - return tern_find_path_default(head, key, def); + return tern_find_path_default(head, key, def, valtype); } tern_node * tern_insert_ptr(tern_node * head, char const * key, void * value) { tern_val val; val.ptrval = value; - return tern_insert(head, key, val); + return tern_insert(head, key, val, TVAL_PTR); } tern_node * tern_insert_node(tern_node *head, char const *key, tern_node *value) { tern_val val; - val.intval = ((intptr_t)value) | 1; - return tern_insert(head, key, val); + val.ptrval = value; + return tern_insert(head, key, val, TVAL_NODE); } uint32_t tern_count(tern_node *head) @@ -184,7 +197,7 @@ { if (!head->el) { keybuf[pos] = 0; - fun(keybuf, head->straight.value, data); + fun(keybuf, head->straight.value, head->valtype, data); } if (head->left) { tern_foreach_int(head->left, fun, data, keybuf, pos); @@ -220,11 +233,6 @@ return buf; } -tern_node * tern_get_node(tern_val value) -{ - return value.intval & 1 ? (tern_node *)(value.intval & ~1) : NULL; -} - void tern_free(tern_node *head) { if (head->left) { @@ -236,4 +244,5 @@ if (head->el) { tern_free(head->straight.next); } + free(head); } diff -r 58bfbed6cdb5 -r 071e761bcdcf tern.h --- a/tern.h Fri Apr 21 01:22:52 2017 -0700 +++ b/tern.h Fri Apr 21 23:35:32 2017 -0700 @@ -23,25 +23,33 @@ } straight; struct tern_node *right; char el; + uint8_t valtype; } tern_node; -typedef void (*iter_fun)(char *key, tern_val val, void *data); +enum { + TVAL_NONE=0, + TVAL_INT, + TVAL_PTR, + TVAL_NODE +}; -tern_node * tern_insert(tern_node * head, char const * key, tern_val value); -int tern_find(tern_node * head, char const * key, tern_val *ret); +typedef void (*iter_fun)(char *key, tern_val val, uint8_t valtype, void *data); + +tern_node * tern_insert(tern_node * head, char const * key, tern_val value, uint8_t valtype); +uint8_t tern_find(tern_node * head, char const * key, tern_val *ret); tern_node * tern_find_prefix(tern_node * head, char const * key); intptr_t tern_find_int(tern_node * head, char const * key, intptr_t def); tern_node * tern_insert_int(tern_node * head, char const * key, intptr_t value); void * tern_find_ptr_default(tern_node * head, char const * key, void * def); void * tern_find_ptr(tern_node * head, char const * key); -tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def); -tern_val tern_find_path(tern_node *head, char const *key); +tern_node *tern_find_node(tern_node *head, char const *key); +tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def, uint8_t req_valtype); +tern_val tern_find_path(tern_node *head, char const *key, uint8_t valtype); tern_node * tern_insert_ptr(tern_node * head, char const * key, void * value); tern_node * tern_insert_node(tern_node *head, char const *key, tern_node *value); uint32_t tern_count(tern_node *head); void tern_foreach(tern_node *head, iter_fun fun, void *data); char * tern_int_key(uint32_t key, char * buf); -tern_node * tern_get_node(tern_val value); void tern_free(tern_node *head); #endif //TERN_H_