diff --git a/4coder_default_framework.h b/4coder_default_framework.h index 0b34865a..4ceb94fc 100644 --- a/4coder_default_framework.h +++ b/4coder_default_framework.h @@ -742,6 +742,18 @@ static Extension_List treat_as_code_exts = {0}; static bool32 automatically_load_project = false; +static char default_compiler_bat_space[256]; +static String default_compiler_bat = make_fixed_width_string(default_compiler_bat_space); + +static char default_flags_bat_space[1024]; +static String default_flags_bat = make_fixed_width_string(default_flags_bat_space); + +static char default_compiler_sh_space[256]; +static String default_compiler_sh = make_fixed_width_string(default_compiler_sh_space); + +static char default_flags_sh_space[1024]; +static String default_flags_sh = make_fixed_width_string(default_flags_sh_space); + static bool32 get_current_name(char **name_out, int32_t *len_out){ bool32 result = false; @@ -813,6 +825,15 @@ process_config_file(Application_Links *app){ Partition *part = &global_part; FILE *file = fopen("config.4coder", "rb"); + static bool32 has_initialized = false; + if (!has_initialized){ + has_initialized = true; + copy(&default_compiler_bat, "cl"); + copy(&default_flags_bat, ""); + copy(&default_compiler_sh, "g++"); + copy(&default_flags_bat, ""); + } + if (file == 0){ char space[256]; int32_t size = get_4ed_path(app, space, sizeof(space)); @@ -868,6 +889,10 @@ process_config_file(Application_Links *app){ config_string_var(item, "default_font_name", 0, &default_font_name); config_string_var(item, "user_name", 0, &user_name); + config_string_var(item, "default_compiler_bat", 0, &default_compiler_bat); + config_string_var(item, "default_flags_bat", 0, &default_flags_bat); + config_string_var(item, "default_compiler_sh", 0, &default_compiler_sh); + config_string_var(item, "default_flags_sh", 0, &default_flags_sh); char str_space[512]; String str = make_fixed_width_string(str_space); diff --git a/4coder_default_include.cpp b/4coder_default_include.cpp index a1ee3e3d..98c23ae2 100644 --- a/4coder_default_include.cpp +++ b/4coder_default_include.cpp @@ -516,6 +516,9 @@ CUSTOM_COMMAND_SIG(execute_arbitrary_command){ else if (match_ss(bar.string, make_lit_string("remap"))){ exec_command(app, remap_interactive); } + else if (match_ss(bar.string, make_lit_string("new project"))){ + exec_command(app, setup_new_project); + } else{ print_message(app, literal("unrecognized command\n")); } diff --git a/4coder_lib/4coder_string.h b/4coder_lib/4coder_string.h index 87b39d63..fd119bb6 100644 --- a/4coder_lib/4coder_string.h +++ b/4coder_lib/4coder_string.h @@ -1,5 +1,5 @@ /* -4coder_string.h - Version 1.0.102 +4coder_string.h - Version 1.0.107 no warranty implied; use at your own risk This software is in the public domain. Where that dedication is not @@ -42,7 +42,7 @@ typedef int32_t b32_4tech; #if !defined(Assert) # define Assert(n) do{ if (!(n)) *(int*)0 = 0xA11E; }while(0) #endif -// standard preamble end +// standard preamble end #if !defined(FSTRING_LINK) # define FSTRING_LINK static @@ -169,6 +169,10 @@ FSTRING_INLINE b32_4tech append_sc(String *dest, char *src); FSTRING_LINK b32_4tech terminate_with_null(String *str); FSTRING_LINK b32_4tech append_padding(String *dest, char c, i32_4tech target_size); FSTRING_LINK void replace_char(String *str, char replace, char with); +FSTRING_LINK void replace_str_ss(String *str, String replace, String with); +FSTRING_LINK void replace_str_sc(String *str, String replace, char *with); +FSTRING_LINK void replace_str_cs(String *str, char *replace, String with); +FSTRING_LINK void replace_str_cc(String *str, char *replace, char *with); FSTRING_LINK void to_lower_cc(char *src, char *dst); FSTRING_LINK void to_lower_ss(String *dst, String src); FSTRING_LINK void to_lower_s(String *str); @@ -272,6 +276,10 @@ FSTRING_LINK b32_4tech append_partial(String *dest, String src){retu FSTRING_LINK b32_4tech append(String *dest, char c){return(append_s_char(dest,c));} FSTRING_INLINE b32_4tech append(String *dest, String src){return(append_ss(dest,src));} FSTRING_INLINE b32_4tech append(String *dest, char *src){return(append_sc(dest,src));} +FSTRING_LINK void replace_str(String *str, String replace, String with){return(replace_str_ss(str,replace,with));} +FSTRING_LINK void replace_str(String *str, String replace, char *with){return(replace_str_sc(str,replace,with));} +FSTRING_LINK void replace_str(String *str, char *replace, String with){return(replace_str_cs(str,replace,with));} +FSTRING_LINK void replace_str(String *str, char *replace, char *with){return(replace_str_cc(str,replace,with));} FSTRING_LINK void to_lower(char *src, char *dst){return(to_lower_cc(src,dst));} FSTRING_LINK void to_lower(String *dst, String src){return(to_lower_ss(dst,src));} FSTRING_LINK void to_lower(String *str){return(to_lower_s(str));} @@ -1472,6 +1480,85 @@ replace_char(String *str, char replace, char with){ } #endif +#if !defined(FSTRING_GUARD) +void +block_move(void *a_ptr, void *b_ptr, i32_4tech s){ + u8_4tech *a = (u8_4tech*)a_ptr; + u8_4tech *b = (u8_4tech*)b_ptr; + if (a < b){ + for (i32_4tech i = 0; i < s; ++i, ++a, ++b){ + *a = *b; + } + } + else if (a > b){ + a = a + s - 1; + b = b + s - 1; + for (i32_4tech i = 0; i < s; ++i, --a, --b){ + *a = *b; + } + } +} + +void +replace_range_str(String *str, i32_4tech first, i32_4tech one_past_last, String with){ + i32_4tech shift = with.size - (one_past_last - first); + i32_4tech new_size = str->size + shift; + if (new_size <= str->memory_size){ + if (shift != 0){ + char *tail = str->str + one_past_last; + char *new_tail_pos = tail + shift; + block_move(new_tail_pos, tail, str->size - one_past_last); + } + block_move(str->str + first, with.str, with.size); + str->size += shift; + } +} +#endif + + +#if defined(FSTRING_IMPLEMENTATION) +FSTRING_LINK void +replace_str_ss(String *str, String replace, String with){ + i32_4tech i = 0; + for (;;){ + i = find_substr_s(*str, i, replace); + if (i >= str->size){ + break; + } + replace_range_str(str, i, i + replace.size, with); + i += with.size; + } +} +#endif + + +#if defined(FSTRING_IMPLEMENTATION) +FSTRING_LINK void +replace_str_sc(String *str, String replace, char *with){ + String w = make_string_slowly(with); + replace_str_ss(str, replace, w); +} +#endif + + +#if defined(FSTRING_IMPLEMENTATION) +FSTRING_LINK void +replace_str_cs(String *str, char *replace, String with){ + String r = make_string_slowly(replace); + replace_str_ss(str, r, with); +} +#endif + + +#if defined(FSTRING_IMPLEMENTATION) +FSTRING_LINK void +replace_str_cc(String *str, char *replace, char *with){ + String r = make_string_slowly(replace); + String w = make_string_slowly(with); + replace_str_ss(str, r, w); +} +#endif + #if defined(FSTRING_IMPLEMENTATION) FSTRING_LINK void @@ -2062,7 +2149,6 @@ remove_last_folder(String *str){ } #endif -// TODO(allen): Add hash-table extension to string sets. #if defined(FSTRING_IMPLEMENTATION) FSTRING_LINK b32_4tech diff --git a/4coder_project_commands.cpp b/4coder_project_commands.cpp index 5256c083..9e136277 100644 --- a/4coder_project_commands.cpp +++ b/4coder_project_commands.cpp @@ -1,20 +1,20 @@ /* -4coder_project_commands.cpp - Commands for loading and using a project. +4coder_project_commands.cpp - commands for loading and using a project. -TYPE: 'drop-in-command-pack' +type: 'drop-in-command-pack' */ -// TOP +// top -#if !defined(FCODER_PROJECT_COMMANDS_CPP) -#define FCODER_PROJECT_COMMANDS_CPP +#if !defined(fcoder_project_commands_cpp) +#define fcoder_project_commands_cpp #include "4coder_default_framework.h" #include "4coder_lib/4coder_mem.h" #include "4coder_build_commands.cpp" -// TODO(allen): make this a string operation or a lexer operation or something +// TODO(allen): Make this a string operation or a lexer operation or something static void interpret_escaped_string(char *dst, String src){ int32_t mode = 0; @@ -46,6 +46,8 @@ interpret_escaped_string(char *dst, String src){ dst[j] = 0; } +/////////////////////////////// + static void close_all_files_with_extension(Application_Links *app, Partition *scratch_part, char **extension_list, int32_t extension_count){ Temp_Memory temp = begin_temp_memory(scratch_part); @@ -91,8 +93,7 @@ close_all_files_with_extension(Application_Links *app, Partition *scratch_part, for (int32_t i = 0; i < buffers_to_close_count; ++i){ kill_buffer(app, buffer_identifier(buffers_to_close[i]), true, 0); } - } - while(do_repeat); + }while(do_repeat); end_temp_memory(temp); } @@ -186,6 +187,8 @@ CUSTOM_COMMAND_SIG(close_all_code){ close_all_files_with_extension(app, &global_part, extension_list, extension_count); } +/////////////////////////////// + static void load_project_from_config_data(Application_Links *app, Partition *part, char *config_data, int32_t config_data_size, String project_dir){ Temp_Memory temp = begin_temp_memory(part); @@ -447,6 +450,8 @@ CUSTOM_COMMAND_SIG(load_project){ end_temp_memory(temp); } +/////////////////////////////// + static void exec_project_fkey_command(Application_Links *app, int32_t command_ind){ Fkey_Command *fkey = ¤t_project.fkey_commands[command_ind]; @@ -530,6 +535,238 @@ CUSTOM_COMMAND_SIG(project_go_to_root_directory){ } } +/////////////////////////////// + +struct Project_Setup_Status{ + bool32 bat_exists; + bool32 sh_exists; + bool32 project_exists; + + bool32 everything_exists; +}; + +static Project_Setup_Status +project_is_setup(Application_Links *app, char *dir, int32_t dir_len, int32_t dir_capacity){ + Project_Setup_Status result = {0}; + + Temp_Memory temp = begin_temp_memory(&global_part); + + static int32_t needed_extra_space = 15; + + String str = {0}; + if (dir_capacity >= dir_len + needed_extra_space){ + str = make_string_cap(dir, dir_len, dir_capacity); + } + else{ + char *space = push_array(&global_part, char, dir_len + needed_extra_space); + str = make_string_cap(space, 0, dir_len + needed_extra_space); + copy(&str, make_string(dir, dir_len)); + } + + str.size = dir_len; + append(&str, "/build.bat"); + result.bat_exists = file_exists(app, str.str, str.size); + + str.size = dir_len; + append(&str, "/build.sh"); + result.sh_exists = file_exists(app, str.str, str.size); + + str.size = dir_len; + append(&str, "/project.4coder"); + result.project_exists = file_exists(app, str.str, str.size); + + result.everything_exists = result.bat_exists && result.sh_exists && result.project_exists; + + end_temp_memory(temp); + + return(result); +} + +// TODO(allen): For this purpose we shouldn't go this far. +// Instead just let the CWD of the running script be the code home. +static char get_code_home[] = +"# Store the real CWD\n" +"REAL_PWD=\"$PWD\"\n\n" +"# Find the code home folder\n" +"TARGET_FILE=\"$0\"\n" +"cd `dirname $TARGET_FILE`\n" +"TARGET_FILE=`basename $TARGET_FILE`\n" +"while [ -L \"$TARGET_FILE\" ]\n" +"do\n" +"TARGET_FILE=`readlink $TARGET_FILE`\n" +"cd `dirname $TARGET_FILE`\n" +"TARGET_FILE=`basename $TARGET_FILE`\n" +"done\n" +"PHYS_DIR=`pwd -P`\n" +"SCRIPT_FILE=$PHYS_DIR/$TARGET_FILE\n" +"CODE_HOME=$(dirname \"$SCRIPT_FILE\")\n\n" +"# Restore the PWD\n" +"cd \"$REAL_PWD\"\n\n"; + +// TODO(allen): Stop using stdio.h, switch to a 4coder buffer API for all file manipulation. +#include +CUSTOM_COMMAND_SIG(setup_new_project){ + char space[4096]; + String str = make_fixed_width_string(space); + str.size = directory_get_hot(app, str.str, str.memory_size); + int32_t dir_size = str.size; + + Project_Setup_Status status = project_is_setup(app, str.str, dir_size, str.memory_size); + if (!status.everything_exists){ + // Query the User for Key File Names + Query_Bar code_file_bar = {0}; + Query_Bar output_dir_bar = {0}; + Query_Bar binary_file_bar = {0}; + char code_file_space[1024]; + char output_dir_space[1024]; + char binary_file_space[1024]; + + if (!status.bat_exists || !status.sh_exists){ + code_file_bar.prompt = make_lit_string("Build Target: "); + code_file_bar.string = make_fixed_width_string(code_file_space); + + if (!query_user_string(app, &code_file_bar)) return; + if (code_file_bar.string.size == 0) return; + } + + output_dir_bar.prompt = make_lit_string("Output Directory: "); + output_dir_bar.string = make_fixed_width_string(output_dir_space); + + if (!query_user_string(app, &output_dir_bar)) return; + if (output_dir_bar.string.size == 0){ + copy(&output_dir_bar.string, "."); + } + + + binary_file_bar.prompt = make_lit_string("Binary Output: "); + binary_file_bar.string = make_fixed_width_string(binary_file_space); + + if (!query_user_string(app, &binary_file_bar)) return; + if (binary_file_bar.string.size == 0) return; + + + String code_file = code_file_bar.string; + String output_dir = output_dir_bar.string; + String binary_file = binary_file_bar.string; + + // Generate Scripts + if (!status.bat_exists){ + replace_char(&code_file, '/', '\\'); + replace_char(&output_dir, '/', '\\'); + replace_char(&binary_file, '/', '\\'); + + str.size = dir_size; + append(&str, "/build.bat"); + terminate_with_null(&str); + FILE *bat_script = fopen(str.str, "wb"); + if (bat_script != 0){ + fprintf(bat_script, "@echo off\n\n"); + fprintf(bat_script, "SET OPTS=%.*s\n", + default_flags_bat.size, default_flags_bat.str); + fprintf(bat_script, "SET CODE_HOME=%%cd%%\n"); + + fprintf(bat_script, "pushd %.*s\n", + output_dir.size, output_dir.str); + fprintf(bat_script, "%.*s %%OPTS%% %%CODE_HOME%%\\%.*s -Fe%.*s\n", + default_compiler_bat.size, default_compiler_bat.str, + code_file.size, code_file.str, + binary_file.size, binary_file.str); + fprintf(bat_script, "popd\n"); + + fclose(bat_script); + } + else{ + print_message(app, literal("could not create build.bat for new project\n")); + } + + replace_char(&code_file, '\\', '/'); + replace_char(&output_dir, '\\', '/'); + replace_char(&binary_file, '\\', '/'); + } + else{ + print_message(app, literal("build.bat already exists, no changes made to it\n")); + } + + if (!status.sh_exists){ + str.size = dir_size; + append(&str, "/build.sh"); + terminate_with_null(&str); + FILE *sh_script = fopen(str.str, "wb"); + if (sh_script != 0){ + fprintf(sh_script, "#!/bin/bash\n\n"); + + fprintf(sh_script, get_code_home); + + fprintf(sh_script, "OPTS=%.*s\n", + default_flags_sh.size, default_flags_sh.str); + + fprintf(sh_script, "pushd %.*s\n", + output_dir.size, output_dir.str); + fprintf(sh_script, "%.*s $OPTS $CODE_HOME/%.*s -o %.*s\n", + default_compiler_sh.size, default_compiler_sh.str, + code_file.size, code_file.str, + binary_file.size, binary_file.str); + fprintf(sh_script, "popd\n"); + + fclose(sh_script); + } + else{ + print_message(app, literal("could not create build.sh for new project\n")); + } + } + else{ + print_message(app, literal("build.sh already exists, no changes made to it\n")); + } + + if (!status.project_exists){ + str.size = dir_size; + append(&str, "/project.4coder"); + terminate_with_null(&str); + FILE *project_script = fopen(str.str, "wb"); + if (project_script != 0){ + fprintf(project_script, "extensions = \".c.cpp.h.m.bat.sh.4coder\";\n"); + fprintf(project_script, "open_recursively = true;\n\n"); + + replace_str(&code_file, "/", "\\\\"); + replace_str(&output_dir, "/", "\\\\"); + replace_str(&binary_file, "/", "\\\\"); + fprintf(project_script, + "fkey_command_win[1] = {\"build.bat\", \"*compilation*\", true , true };\n"); + fprintf(project_script, + "fkey_command_win[2] = {\"%.*s\\\\%.*s\", \"*run*\", false , true };\n", + output_dir.size, output_dir.str, + binary_file.size, binary_file.str); + replace_str(&code_file, "\\\\", "/"); + replace_str(&output_dir, "\\\\", "/"); + replace_str(&binary_file, "\\\\", "/"); + + fprintf(project_script, "fkey_command_linux[1] = {\"build.sh\", \"*compilation*\", true , true };\n"); + fprintf(project_script, + "fkey_command_linux[2] = {\"%.*s/%.*s\", \"*run*\", false , true };\n", + output_dir.size, output_dir.str, + binary_file.size, binary_file.str); + + fprintf(project_script, "fkey_command_mac[1] = {\"build.sh\", \"*compilation*\", true , true };\n"); + fprintf(project_script, + "fkey_command_mac[2] = {\"%.*s/%.*s\", \"*run*\", false , true };\n", + output_dir.size, output_dir.str, + binary_file.size, binary_file.str); + fclose(project_script); + } + else{ + print_message(app, literal("could not create project.4coder for new project\n")); + } + } + else{ + print_message(app, literal("project.4coder already exists, no changes made to it\n")); + } + + } + else{ + print_message(app, literal("project already setup, no changes made\n")); + } +} + #endif // BOTTOM diff --git a/project.4coder b/project.4coder index 5fe1c33e..e8b251d8 100644 --- a/project.4coder +++ b/project.4coder @@ -1,5 +1,5 @@ -extensions=".c.cpp.h.m.bat.sh.4coder"; -open_recursively=true; +extensions = ".c.cpp.h.m.bat.sh.4coder"; +open_recursively = true; fkey_command_win[1] = {"echo build: x64 & build.bat", "*compilation*" , true , true }; fkey_command_win[2] = {"build_site.bat" , "*site*" , false, true }; diff --git a/release-config.4coder b/release-config.4coder index b2ed8320..bf3190e5 100644 --- a/release-config.4coder +++ b/release-config.4coder @@ -35,3 +35,10 @@ automatically_load_project = false; // Keyboard AltGr setting lalt_lctrl_is_altgr = false; + +// Project setup configuration +default_compiler_bat = "cl"; +default_flags_bat = "-FC -GR- -EHa- -nologo -Zi"; +default_compiler_sh = "g++"; +default_flags_sh = "-g"; + diff --git a/string/4coder_string_build_num.txt b/string/4coder_string_build_num.txt index f67272eb..d5e6514d 100644 --- a/string/4coder_string_build_num.txt +++ b/string/4coder_string_build_num.txt @@ -1,5 +1,5 @@ 1 0 -104 +108 diff --git a/string/internal_4coder_string.cpp b/string/internal_4coder_string.cpp index 950438da..3669cd14 100644 --- a/string/internal_4coder_string.cpp +++ b/string/internal_4coder_string.cpp @@ -1246,6 +1246,77 @@ DOC(This call replaces all occurances of character in str with another character } } +#if !defined(FSTRING_GUARD) +void +block_move(void *a_ptr, void *b_ptr, i32_4tech s){ + u8_4tech *a = (u8_4tech*)a_ptr; + u8_4tech *b = (u8_4tech*)b_ptr; + if (a < b){ + for (i32_4tech i = 0; i < s; ++i, ++a, ++b){ + *a = *b; + } + } + else if (a > b){ + a = a + s - 1; + b = b + s - 1; + for (i32_4tech i = 0; i < s; ++i, --a, --b){ + *a = *b; + } + } +} + +void +replace_range_str(String *str, i32_4tech first, i32_4tech one_past_last, String with){ + i32_4tech shift = with.size - (one_past_last - first); + i32_4tech new_size = str->size + shift; + if (new_size <= str->memory_size){ + if (shift != 0){ + char *tail = str->str + one_past_last; + char *new_tail_pos = tail + shift; + block_move(new_tail_pos, tail, str->size - one_past_last); + } + block_move(str->str + first, with.str, with.size); + str->size += shift; + } +} +#endif + +CPP_NAME(replace_str) +API_EXPORT FSTRING_LINK void +replace_str_ss(String *str, String replace, String with){ + i32_4tech i = 0; + for (;;){ + i = find_substr_s(*str, i, replace); + if (i >= str->size){ + break; + } + replace_range_str(str, i, i + replace.size, with); + i += with.size; + } +} + +CPP_NAME(replace_str) +API_EXPORT FSTRING_LINK void +replace_str_sc(String *str, String replace, char *with){ + String w = make_string_slowly(with); + replace_str_ss(str, replace, w); +} + +CPP_NAME(replace_str) +API_EXPORT FSTRING_LINK void +replace_str_cs(String *str, char *replace, String with){ + String r = make_string_slowly(replace); + replace_str_ss(str, r, with); +} + +CPP_NAME(replace_str) +API_EXPORT FSTRING_LINK void +replace_str_cc(String *str, char *replace, char *with){ + String r = make_string_slowly(replace); + String w = make_string_slowly(with); + replace_str_ss(str, r, w); +} + CPP_NAME(to_lower) API_EXPORT FSTRING_LINK void to_lower_cc(char *src, char *dst)/*