/* 4coder_prj_v1.cpp - parsing and converting v0 and v1 projects */ // TOP //////////////////////////////// // NOTE(allen): Project v0-v1 Functions function void prj_v1_parse_pattern_list(Arena *arena, Config *parsed, char *name, Prj_Pattern_List *list_out){ Config_Compound *compound = 0; if (config_compound_var(parsed, name, 0, &compound)){ Config_Get_Result_List list = typed_string_array_reference_list(arena, parsed, compound); for (Config_Get_Result_Node *cfg_node = list.first; cfg_node != 0; cfg_node = cfg_node->next){ Prj_Pattern_Node *node = push_array(arena, Prj_Pattern_Node, 1); sll_queue_push(list_out->first, list_out->last, node); list_out->count += 1; String8 str = push_string_copy(arena, cfg_node->result.string); node->pattern.absolutes = string_split_wildcards(arena, str); } } } function Prj_V1_OS_Match_Level prj_v1_parse_os_match(String8 str, String8 this_os_str){ Prj_V1_OS_Match_Level result = PrjV1OSMatchLevel_NoMatch; if (string_match(str, this_os_str)){ result = PrjV1OSMatchLevel_ActiveMatch; } else if (string_match(str, string_u8_litexpr("all"))){ result = PrjV1OSMatchLevel_ActiveMatch; } else if (string_match(str, string_u8_litexpr("default"))){ result = PrjV1OSMatchLevel_PassiveMatch; } return(result); } function Prj_V1* prj_v1_parse_from_config(Application_Links *app, Arena *arena, String8 dir, Config *parsed){ Prj_V1 *project = push_array_zero(arena, Prj_V1, 1); // Set new project directory project->dir = push_string_copy(arena, dir); // project_name { String8 str = {}; if (config_string_var(parsed, "project_name", 0, &str)){ project->name = push_string_copy(arena, str); } else{ project->name = SCu8(""); } } // patterns prj_v1_parse_pattern_list(arena, parsed, "patterns", &project->pattern_list); // blacklist_patterns prj_v1_parse_pattern_list(arena, parsed, "blacklist_patterns", &project->blacklist_pattern_list); // load_paths { Config_Compound *compound = 0; if (config_compound_var(parsed, "load_paths", 0, &compound)){ b32 found_match = false; Config_Compound *best_paths = 0; for (i32 i = 0;; ++i){ Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, compound, ConfigRValueType_Compound, i); if (result.step == Iteration_Skip){ continue; } else if (result.step == Iteration_Quit){ break; } Config_Compound *paths_option = result.get.compound; Config_Compound *paths = 0; if (config_compound_compound_member(parsed, paths_option, "paths", 0, &paths)){ String8 str = {}; if (config_compound_string_member(parsed, paths_option, "os", 1, &str)){ Prj_V1_OS_Match_Level r = prj_v1_parse_os_match(str, string_u8_litexpr(OS_NAME)); if (r == PrjV1OSMatchLevel_ActiveMatch){ found_match = true; best_paths = paths; break; } else if (r == PrjV1OSMatchLevel_PassiveMatch){ if (!found_match){ found_match = true; best_paths = paths; } } } } } if (found_match){ Config_Get_Result_List list = typed_compound_array_reference_list(arena, parsed, best_paths); project->load_path_array.paths = push_array(arena, Prj_V1_File_Load_Path, list.count); project->load_path_array.count = list.count; Prj_V1_File_Load_Path *dst = project->load_path_array.paths; for (Config_Get_Result_Node *node = list.first; node != 0; node = node->next, ++dst){ Config_Compound *src = node->result.compound; block_zero_struct(dst); dst->recursive = true; dst->relative = true; String8 str = {}; if (config_compound_string_member(parsed, src, "path", 0, &str)){ dst->path = push_string_copy(arena, str); } config_compound_bool_member(parsed, src, "recursive", 1, &dst->recursive); config_compound_bool_member(parsed, src, "relative", 2, &dst->relative); } } } } // command_list { Config_Compound *compound = 0; if (config_compound_var(parsed, "command_list", 0, &compound)){ Config_Get_Result_List list = typed_compound_array_reference_list(arena, parsed, compound); project->command_array.commands = push_array(arena, Prj_V1_Command, list.count); project->command_array.count = list.count; Prj_V1_Command *dst = project->command_array.commands; for (Config_Get_Result_Node *node = list.first; node != 0; node = node->next, ++dst){ u8 *pos = node->result.pos; Config_Compound *src = node->result.compound; block_zero_struct(dst); b32 can_emit_command = true; Config_Get_Result cmd_result = {}; Config_Compound *cmd_set = 0; u8 *cmd_pos = 0; String8 cmd_str = {}; String8 out = {}; b32 footer_panel = false; b32 save_dirty_files = true; b32 cursor_at_end = false; String8 name = {}; if (!config_compound_string_member(parsed, src, "name", 0, &name)){ can_emit_command = false; def_config_push_error(arena, parsed, pos, "a command must have a string type name member"); goto finish_command; } cmd_result = config_compound_member(parsed, src, string_u8_litexpr("cmd"), 1); if (cmd_result.success && cmd_result.type == ConfigRValueType_Compound){ cmd_set = cmd_result.compound; cmd_pos = cmd_result.pos; } else{ can_emit_command = false; def_config_push_error(arena, parsed, pos, "a command must have an array type cmd member"); goto finish_command; } can_emit_command = false; for (i32 j = 0;; ++j){ Config_Iteration_Step_Result result = typed_array_iteration_step(parsed, cmd_set, ConfigRValueType_Compound, j); if (result.step == Iteration_Skip){ continue; } else if (result.step == Iteration_Quit){ break; } Config_Compound *cmd_option = result.get.compound; String8 cmd = {}; if (config_compound_string_member(parsed, cmd_option, "cmd", 0, &cmd)){ String8 str = {}; if (config_compound_string_member(parsed, cmd_option, "os", 1, &str)){ Prj_V1_OS_Match_Level r = prj_v1_parse_os_match(str, string_u8_litexpr(OS_NAME)); if (r == PrjV1OSMatchLevel_ActiveMatch){ can_emit_command = true; cmd_str = cmd; break; } else if (r == PrjV1OSMatchLevel_PassiveMatch){ if (!can_emit_command){ can_emit_command = true; cmd_str = cmd; } } } } } if (!can_emit_command){ def_config_push_error(arena, parsed, cmd_pos, "no usable command strings found in cmd"); goto finish_command; } config_compound_string_member(parsed, src, "out", 2, &out); config_compound_bool_member(parsed, src, "footer_panel", 3, &footer_panel); config_compound_bool_member(parsed, src, "save_dirty_files", 4, &save_dirty_files); config_compound_bool_member(parsed, src, "cursor_at_end", 5, &cursor_at_end); dst->name = push_string_copy(arena, name); dst->cmd = push_string_copy(arena, cmd_str); dst->out = push_string_copy(arena, out); dst->footer_panel = footer_panel; dst->save_dirty_files = save_dirty_files; dst->cursor_at_end = cursor_at_end; finish_command:; } } } // fkey_command { for (i32 i = 1; i <= 16; ++i){ String8 name = {}; i32 index = -1; if (config_string_var(parsed, "fkey_command", i, &name)){ i32 count = project->command_array.count; Prj_V1_Command *command_ptr = project->command_array.commands; for (i32 j = 0; j < count; ++j, ++command_ptr){ if (string_match(command_ptr->name, name)){ index = j; break; } } } project->fkey_commands[i - 1] = index; } } project->loaded = true; return(project); } #if 0 function void project_v1_deep_copy__pattern_list(Arena *arena, Prj_Pattern_List *src_list, Prj_Pattern_List *dst_list){ for (Prj_Pattern_Node *src_node = src_list->first; src_node != 0; src_node = src_node->next){ Prj_Pattern_Node *dst_node = push_array(arena, Prj_Pattern_Node, 1); sll_queue_push(dst_list->first, dst_list->last, dst_node); dst_list->count += 1; for (String8Node *node = src_node->pattern.absolutes.first; node != 0; node = node->next){ String8 string = push_string_copy(arena, node->string); string_list_push(arena, &dst_node->pattern.absolutes, string); } } } function Prj project_v1_deep_copy__inner(Arena *arena, Prj *project){ Prj result = {}; result.dir = push_string_copy(arena, project->dir); result.name = push_string_copy(arena, project->name); project_deep_copy__pattern_list(arena, &project->pattern_list, &result.pattern_list); project_deep_copy__pattern_list(arena, &project->blacklist_pattern_list, &result.blacklist_pattern_list); { i32 path_count = project->load_path_array.count; result.load_path_array.paths = push_array(arena, Prj_File_Load_Path, path_count); result.load_path_array.count = path_count; Prj_File_Load_Path *dst = result.load_path_array.paths; Prj_File_Load_Path *src = project->load_path_array.paths; for (i32 i = 0; i < path_count; ++i, ++dst, ++src){ dst->path = push_string_copy(arena, src->path); dst->recursive = src->recursive; dst->relative = src->relative; } } { i32 command_count = project->command_array.count; result.command_array.commands = push_array_zero(arena, Prj_Command, command_count); result.command_array.count = command_count; Prj_Command *dst = result.command_array.commands; Prj_Command *src = project->command_array.commands; for (i32 i = 0; i < command_count; ++i, ++dst, ++src){ if (src->name.str != 0){ dst->name = push_string_copy(arena, src->name); } if (src->cmd.str != 0){ dst->cmd = push_string_copy(arena, src->cmd); } if (src->out.str != 0){ dst->out = push_string_copy(arena, src->out); } dst->footer_panel = src->footer_panel; dst->save_dirty_files = src->save_dirty_files; dst->cursor_at_end = src->cursor_at_end; } } block_copy_array(result.fkey_commands, project->fkey_commands); result.loaded = true; return(result); } function Prj project_v1_deep_copy(Arena *arena, Prj *project){ Temp_Memory restore_point = begin_temp(arena); Prj result = project_deep_copy__inner(arena, project); if (!result.loaded){ end_temp(restore_point); block_zero_struct(&result); } return(result); } #endif // NOTE(allen): string list join ("flatten") doesn't really work... :( function String8 prj_v1_join_pattern_string(Arena *arena, String8List list){ String8 pattern_string = {}; pattern_string.size = list.total_size + list.node_count - 1; pattern_string.str = push_array(arena, u8, pattern_string.size + 1); u8 *ptr = pattern_string.str; String8Node *node = list.first; if (node != 0){ for (;;){ block_copy(ptr, node->string.str, node->string.size); ptr += node->string.size; node = node->next; if (node == 0){ break; } *ptr = '*'; ptr += 1; } } pattern_string.str[pattern_string.size] = 0; return(pattern_string); } function String8 prj_v1_sanitize_string(Arena *arena, String8 string){ String8 result = {}; if (string.size > 0){ result.size = string.size; result.str = push_array(arena, u8, result.size + 2); u8 *in = string.str; u8 *out = result.str; if (character_is_base10(*in)){ *out = '_'; out += 1; result.size += 1; } for (u64 i = 0; i < string.size; i += 1, in += 1, out += 1){ u8 c = *in; if (!character_is_alpha_numeric(c)){ c = '_'; } *out = c; } result.str[result.size] = 0; } return(result); } function Variable_Handle prj_v1_to_v2(Application_Links *app, String8 dir, Config *parsed){ Scratch_Block scratch(app); Prj_V1 *project = prj_v1_parse_from_config(app, scratch, dir, parsed); String_ID project_id = vars_save_string_lit("prj_config"); String_ID version_id = vars_save_string(str8_lit("version")); String_ID project_name_id = vars_save_string(str8_lit("project_name")); String_ID patterns_id = vars_save_string(str8_lit("patterns")); String_ID blacklist_patterns_id = vars_save_string(str8_lit("blacklist_patterns")); String_ID load_paths_id = vars_save_string(str8_lit("load_paths")); String_ID path_id = vars_save_string(str8_lit("path")); String_ID recursive_id = vars_save_string(str8_lit("recursive")); String_ID relative_id = vars_save_string(str8_lit("relative")); String_ID true_id = vars_save_string(str8_lit("true")); String_ID false_id = vars_save_string(str8_lit("false")); String_ID commands_id = vars_save_string(str8_lit("commands")); String_ID out_id = vars_save_string(str8_lit("out")); String_ID footer_panel_id = vars_save_string(str8_lit("footer_panel")); String_ID save_dirty_files_id = vars_save_string(str8_lit("save_dirty_files")); String_ID cursor_at_end_id = vars_save_string(str8_lit("cursor_at_end")); String_ID fkey_command_id = vars_save_string(str8_lit("fkey_command")); String_ID os_id = vars_save_string(str8_lit(OS_NAME));; Variable_Handle proj_var = vars_new_variable(vars_get_root(), project_id, vars_save_string(parsed->file_name)); if (parsed->version != 0){ String8 version_str = push_stringf(scratch, "%d", *parsed->version); vars_new_variable(proj_var, version_id, vars_save_string(version_str)); } vars_new_variable(proj_var, project_name_id, vars_save_string(project->name)); // NOTE(allen): Load Pattern struct PatternVars{ String_ID id; Prj_Pattern_List list; }; PatternVars pattern_vars[] = { { patterns_id, project-> pattern_list}, {blacklist_patterns_id, project->blacklist_pattern_list}, }; PatternVars *pattern_var = pattern_vars; PatternVars *opl = pattern_vars + ArrayCount(pattern_vars); for (; pattern_var < opl; pattern_var += 1){ Variable_Handle patterns = vars_new_variable(proj_var, pattern_var->id); i32 i = 0; for (Prj_Pattern_Node *node = pattern_var->list.first; node != 0; node = node->next, i += 1){ String8 pattern_string = prj_v1_join_pattern_string(scratch, node->pattern.absolutes); String_ID key = vars_save_string(push_stringf(scratch, "%d", i)); String_ID pattern_id = vars_save_string(pattern_string); vars_new_variable(patterns, key, pattern_id); } } // NOTE(allen): Load Paths { Variable_Handle load_paths = vars_new_variable(proj_var, load_paths_id); Variable_Handle os_var = vars_new_variable(load_paths, os_id); i32 count = project->load_path_array.count; Prj_V1_File_Load_Path *load_path = project->load_path_array.paths; for (i32 i = 0; i < count; i += 1, load_path += 1){ String_ID key = vars_save_string(push_stringf(scratch, "%d", i)); Variable_Handle path_var = vars_new_variable(os_var, key); vars_new_variable(path_var, path_id, vars_save_string(load_path->path)); vars_new_variable(path_var, recursive_id, load_path->recursive?true_id:false_id); vars_new_variable(path_var, relative_id, load_path->recursive?true_id:false_id); } } // NOTE(allen): Commands { Variable_Handle cmd_list_var = vars_new_variable(proj_var, commands_id); i32 count = project->command_array.count; Prj_V1_Command *cmd = project->command_array.commands; for (i32 i = 0; i < count; i += 1, cmd += 1){ String8 cmd_name = prj_v1_sanitize_string(scratch, cmd->name); Variable_Handle cmd_var = vars_new_variable(cmd_list_var, vars_save_string(cmd_name)); vars_new_variable(cmd_var, os_id, vars_save_string(cmd->cmd)); vars_new_variable(cmd_var, out_id, vars_save_string(cmd->out)); vars_new_variable(cmd_var, footer_panel_id, cmd->footer_panel?true_id:false_id); vars_new_variable(cmd_var, save_dirty_files_id, cmd->save_dirty_files?true_id:false_id); vars_new_variable(cmd_var, cursor_at_end_id, cmd->cursor_at_end?true_id:false_id); } } // NOTE(allen): FKey Commands { Variable_Handle fkeys_var = vars_new_variable(proj_var, fkey_command_id); for (i32 i = 0; i < 16; i += 1){ i32 cmd_index = project->fkey_commands[i]; if (0 <= cmd_index && cmd_index < project->command_array.count){ Prj_V1_Command *cmd = project->command_array.commands + cmd_index; if (cmd->name.size > 0){ String8 cmd_name = prj_v1_sanitize_string(scratch, cmd->name); String_ID key = vars_save_string(push_stringf(scratch, "%d", i)); String_ID val = vars_save_string(cmd_name); vars_new_variable(fkeys_var, key, val); } } } } return(proj_var); } // BOTTOM