diff --git a/4coder_custom.cpp b/4coder_custom.cpp index 262ba8d7..eed6a3aa 100644 --- a/4coder_custom.cpp +++ b/4coder_custom.cpp @@ -1,318 +1,317 @@ -/* - * Example use of customization API - */ - -#define FCPP_STRING_IMPLEMENTATION -#include "4coder_string.h" - -#include "4coder_custom.h" -#include "4coder_helper.h" - -#ifndef literal -#define literal(s) s, (sizeof(s)-1) -#endif - -// NOTE(allen|a3.1): All of your custom ids should be >= mapid_user_custom. -// I recommend enumerating your own map ids as shown here. -enum My_Maps{ - my_code_map = mapid_user_custom, - my_html_map -}; - -HOOK_SIG(my_start){ - exec_command(cmd_context, cmdid_open_panel_vsplit); - exec_command(cmd_context, cmdid_change_active_panel); -} - -char *get_extension(const char *filename, int len, int *extension_len){ - char *c = (char*)(filename + len - 1); - char *end = c; - while (*c != '.' && c > filename) --c; - *extension_len = (int)(end - c); - return c+1; -} - -bool str_match(const char *a, int len_a, const char *b, int len_b){ - bool result = 0; - if (len_a == len_b){ - char *end = (char*)(a + len_a); - while (a < end && *a == *b){ - ++a; ++b; - } - if (a == end) result = 1; - } - return result; -} - -HOOK_SIG(my_file_settings){ - Buffer_Summary buffer = get_active_buffer(cmd_context); - - int treat_as_code = 0; - - // NOTE(allen|a3.1): This checks buffer.file_name just in case get_active_buffer returns back - // a null buffer (where every member is 0). - if (buffer.file_name && buffer.size < (16 << 20)){ - int extension_len; - char *extension = get_extension(buffer.file_name, buffer.file_name_len, &extension_len); - if (str_match(extension, extension_len, literal("cpp"))) treat_as_code = 1; - else if (str_match(extension, extension_len, literal("h"))) treat_as_code = 1; - else if (str_match(extension, extension_len, literal("c"))) treat_as_code = 1; - else if (str_match(extension, extension_len, literal("hpp"))) treat_as_code = 1; - } - - push_parameter(app, cmd_context, par_lex_as_cpp_file, treat_as_code); - push_parameter(app, cmd_context, par_wrap_lines, !treat_as_code); - push_parameter(app, cmd_context, par_key_mapid, (treat_as_code)?(my_code_map):(mapid_file)); - exec_command(cmd_context, cmdid_set_settings); -} - -CUSTOM_COMMAND_SIG(open_in_other){ - exec_command(cmd_context, cmdid_change_active_panel); - exec_command(cmd_context, cmdid_interactive_open); -} - -CUSTOM_COMMAND_SIG(open_my_files){ - // NOTE(allen|a3.1): The command cmdid_interactive_open can now open - // a file specified on the parameter stack. If the file does not - // exist cmdid_interactive_open behaves as usual. - push_parameter(app, cmd_context, par_name, literal("w:/4ed/data/test/basic.cpp")); - exec_command(cmd_context, cmdid_interactive_open); - - exec_command(cmd_context, cmdid_change_active_panel); - - char my_file[256]; - int my_file_len; - - my_file_len = sizeof("w:/4ed/data/test/basic.txt") - 1; - for (int i = 0; i < my_file_len; ++i){ - my_file[i] = ("w:/4ed/data/test/basic.txt")[i]; - } - - // NOTE(allen|a3.1): null terminators are not needed for strings. - push_parameter(app, cmd_context, par_name, my_file, my_file_len); - exec_command(cmd_context, cmdid_interactive_open); - - exec_command(cmd_context, cmdid_change_active_panel); -} - -CUSTOM_COMMAND_SIG(build_at_launch_location){ - // NOTE(allen|a3.3): An example of calling build by setting all - // parameters directly. This only works if build.bat can be called - // from the starting directory - push_parameter(app, cmd_context, par_cli_overlap_with_conflict, 1); - push_parameter(app, cmd_context, par_target_buffer_name, literal("*compilation*")); - push_parameter(app, cmd_context, par_cli_path, literal(".")); - push_parameter(app, cmd_context, par_cli_command, literal("build")); - exec_command(cmd_context, cmdid_build); -} - -CUSTOM_COMMAND_SIG(build_search){ - // NOTE(allen|a3.3): An example of traversing the filesystem through parent - // directories looking for a file, in this case a batch file to execute. - // - // - // Step 1: push_directory returns a String containing the current "hot" directory - // (whatever directory you most recently visited in the 4coder file browsing interface) - // - // Step 2: app->directory_has_file queries the file system to see if "build.bat" exists - // If it does exist several parameters are pushed: - // - par_cli_overlap_with_conflict: whether to launch this process if an existing process - // is already being used for output on the same buffer - // - // - par_target_buffer_name: the name of the buffer to fill with the output from the process - // - // - par_cli_path: sets the path from which the command is executed - // - // - par_cli_command: sets the actual command to be executed, this can be almost any command - // that you could execute through a command line interface - // - // - // To set par_cli_path: push_parameter makes a copy of the dir string on the stack - // because the string allocated by push_directory is going to change again - // To set par_cli_command: app->push_parameter does not make a copy of the dir because - // dir isn't going to change again. - // - // Step 3: If the batch file did not exist try to move to the parent directory using - // app->directory_cd. The cd function can also be used to navigate to subdirectories. - // It returns true if it can actually move in the specified direction, and false otherwise. - - int keep_going = 1; - String dir = push_directory(app, cmd_context); - while (keep_going){ - if (app->directory_has_file(dir, "build.bat")){ - push_parameter(app, cmd_context, par_cli_overlap_with_conflict, 0); - push_parameter(app, cmd_context, par_target_buffer_name, literal("*compilation*")); - push_parameter(app, cmd_context, par_cli_path, dir.str, dir.size); - - if (append(&dir, "build")){ - app->push_parameter(cmd_context, - dynamic_int(par_cli_command), - dynamic_string(dir.str, dir.size)); - exec_command(cmd_context, cmdid_build); - } - else{ - clear_parameters(cmd_context); - } - - return; - } - - if (app->directory_cd(&dir, "..") == 0){ - keep_going = 0; - } - } - - // TODO(allen): feedback message - couldn't find build.bat -} - -CUSTOM_COMMAND_SIG(write_and_auto_tab){ - exec_command(cmd_context, cmdid_write_character); - exec_command(cmd_context, cmdid_auto_tab_line_at_cursor); -} - -extern "C" GET_BINDING_DATA(get_bindings){ - Bind_Helper context_actual = begin_bind_helper(data, size); - Bind_Helper *context = &context_actual; - - // NOTE(allen|a3.1): Right now hooks have no loyalties to maps, all hooks are - // global and once set they always apply, regardless of what map is active. - set_hook(context, hook_start, my_start); - set_hook(context, hook_open_file, my_file_settings); - - begin_map(context, mapid_global); - - bind(context, 'p', MDFR_CTRL, cmdid_open_panel_vsplit); - bind(context, '-', MDFR_CTRL, cmdid_open_panel_hsplit); - bind(context, 'P', MDFR_CTRL, cmdid_close_panel); - bind(context, 'n', MDFR_CTRL, cmdid_interactive_new); - bind(context, 'o', MDFR_CTRL, cmdid_interactive_open); - bind(context, ',', MDFR_CTRL, cmdid_change_active_panel); - bind(context, 'k', MDFR_CTRL, cmdid_interactive_kill_buffer); - bind(context, 'i', MDFR_CTRL, cmdid_interactive_switch_buffer); - bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker); - bind(context, 'x', MDFR_ALT, cmdid_open_menu); - bind_me(context, 'o', MDFR_ALT, open_in_other); - - // NOTE(allen): These callbacks may not actually be useful to you, but - // go look at them and see what they do. - bind_me(context, 'M', MDFR_ALT | MDFR_CTRL, open_my_files); - bind_me(context, 'M', MDFR_ALT, build_at_launch_location); - bind_me(context, 'm', MDFR_ALT, build_search); - - end_map(context); - - - begin_map(context, my_code_map); - - // NOTE(allen|a3.1): Set this map (my_code_map == mapid_user_custom) to - // inherit from mapid_file. When searching if a key is bound - // in this map, if it is not found here it will then search mapid_file. - // - // If this is not set, it defaults to mapid_global. - inherit_map(context, mapid_file); - - // NOTE(allen|a3.1): Children can override parent's bindings. - bind(context, codes->right, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_right); - bind(context, codes->left, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_left); - - // NOTE(allen|a3.2): Specific keys can override vanilla keys, - // and write character writes whichever character corresponds - // to the key that triggered the command. - bind_me(context, '\n', MDFR_NONE, write_and_auto_tab); - bind_me(context, '}', MDFR_NONE, write_and_auto_tab); - bind_me(context, ')', MDFR_NONE, write_and_auto_tab); - bind_me(context, ']', MDFR_NONE, write_and_auto_tab); - bind_me(context, ';', MDFR_NONE, write_and_auto_tab); - -#if 0 - bind(context, '\t', MDFR_NONE, cmdid_auto_tab_line_at_cursor); - bind(context, '\t', MDFR_CTRL, cmdid_auto_tab_range); - bind(context, '\t', MDFR_CTRL | MDFR_SHIFT, cmdid_write_character); -#endif - - end_map(context); - - - begin_map(context, mapid_file); - - // NOTE(allen|a3.1): Binding this essentially binds all key combos that - // would normally insert a character into a buffer. - // Or apply this rule (which always works): if the code for the key - // is not in the codes struct, it is a vanilla key. - // It is possible to override this binding for individual keys. - bind_vanilla_keys(context, cmdid_write_character); - - bind(context, codes->left, MDFR_NONE, cmdid_move_left); - bind(context, codes->right, MDFR_NONE, cmdid_move_right); - bind(context, codes->del, MDFR_NONE, cmdid_delete); - bind(context, codes->back, MDFR_NONE, cmdid_backspace); - bind(context, codes->up, MDFR_NONE, cmdid_move_up); - bind(context, codes->down, MDFR_NONE, cmdid_move_down); - bind(context, codes->end, MDFR_NONE, cmdid_seek_end_of_line); - bind(context, codes->home, MDFR_NONE, cmdid_seek_beginning_of_line); - bind(context, codes->page_up, MDFR_NONE, cmdid_page_up); - bind(context, codes->page_down, MDFR_NONE, cmdid_page_down); - - bind(context, codes->right, MDFR_CTRL, cmdid_seek_whitespace_right); - bind(context, codes->left, MDFR_CTRL, cmdid_seek_whitespace_left); - bind(context, codes->up, MDFR_CTRL, cmdid_seek_whitespace_up); - bind(context, codes->down, MDFR_CTRL, cmdid_seek_whitespace_down); - - bind(context, ' ', MDFR_CTRL, cmdid_set_mark); - bind(context, 'm', MDFR_CTRL, cmdid_cursor_mark_swap); - bind(context, 'c', MDFR_CTRL, cmdid_copy); - bind(context, 'x', MDFR_CTRL, cmdid_cut); - bind(context, 'v', MDFR_CTRL, cmdid_paste); - bind(context, 'V', MDFR_CTRL, cmdid_paste_next); - bind(context, 'Z', MDFR_CTRL, cmdid_timeline_scrub); - bind(context, 'z', MDFR_CTRL, cmdid_undo); - bind(context, 'y', MDFR_CTRL, cmdid_redo); - bind(context, codes->left, MDFR_ALT, cmdid_increase_rewind_speed); - bind(context, codes->right, MDFR_ALT, cmdid_increase_fastforward_speed); - bind(context, codes->down, MDFR_ALT, cmdid_stop_rewind_fastforward); - bind(context, 'h', MDFR_CTRL, cmdid_history_backward); - bind(context, 'H', MDFR_CTRL, cmdid_history_forward); - bind(context, 'd', MDFR_CTRL, cmdid_delete_range); - bind(context, 'l', MDFR_CTRL, cmdid_toggle_line_wrap); - bind(context, 'L', MDFR_CTRL, cmdid_toggle_endline_mode); - bind(context, 'u', MDFR_CTRL, cmdid_to_uppercase); - bind(context, 'j', MDFR_CTRL, cmdid_to_lowercase); - bind(context, '?', MDFR_CTRL, cmdid_toggle_show_whitespace); - - bind(context, '~', MDFR_CTRL, cmdid_clean_all_lines); - // NOTE(allen|a3.2): These now only set the mode of the file for writing to disk - // they do no longer effect the internal representation. - bind(context, '1', MDFR_CTRL, cmdid_eol_dosify); - bind(context, '!', MDFR_CTRL, cmdid_eol_nixify); - - bind(context, 'f', MDFR_CTRL, cmdid_search); - bind(context, 'r', MDFR_CTRL, cmdid_rsearch); - bind(context, 'g', MDFR_CTRL, cmdid_goto_line); - - bind(context, 'K', MDFR_CTRL, cmdid_kill_buffer); - bind(context, 'O', MDFR_CTRL, cmdid_reopen); - bind(context, 'w', MDFR_CTRL, cmdid_interactive_save_as); - bind(context, 's', MDFR_CTRL, cmdid_save); - - end_map(context); - end_bind_helper(context); - - return context->write_total; -} - -inline void -strset_(char *dst, char *src){ - do{ - *dst++ = *src++; - }while (*src); -} - -#define strset(d,s) if (sizeof(s) <= sizeof(d)) strset_(d,s) - -extern "C" SET_EXTRA_FONT_SIG(set_extra_font){ - strset(font_out->file_name, "liberation-mono.ttf"); - strset(font_out->font_name, "BIG"); - font_out->size = 25; -} - - +/* + * Example use of customization API + */ + +#define FCPP_STRING_IMPLEMENTATION +#include "4coder_string.h" + +#include "4coder_custom.h" +#include "4coder_helper.h" + +#ifndef literal +#define literal(s) s, (sizeof(s)-1) +#endif + +// NOTE(allen|a3.3): All of your custom ids should be enumerated +// as shown here, they may start at 0, and you can only have +// 2^24 of them so don't be wasteful! +enum My_Maps{ + my_code_map, + my_html_map +}; + +HOOK_SIG(my_start){ + exec_command(cmd_context, cmdid_open_panel_vsplit); + exec_command(cmd_context, cmdid_change_active_panel); +} + +char *get_extension(const char *filename, int len, int *extension_len){ + char *c = (char*)(filename + len - 1); + char *end = c; + while (*c != '.' && c > filename) --c; + *extension_len = (int)(end - c); + return c+1; +} + +bool str_match(const char *a, int len_a, const char *b, int len_b){ + bool result = 0; + if (len_a == len_b){ + char *end = (char*)(a + len_a); + while (a < end && *a == *b){ + ++a; ++b; + } + if (a == end) result = 1; + } + return result; +} + +HOOK_SIG(my_file_settings){ + Buffer_Summary buffer = get_active_buffer(cmd_context); + + int treat_as_code = 0; + + // NOTE(allen|a3.1): This checks buffer.file_name just in case get_active_buffer returns back + // a null buffer (where every member is 0). + if (buffer.file_name && buffer.size < (16 << 20)){ + int extension_len; + char *extension = get_extension(buffer.file_name, buffer.file_name_len, &extension_len); + if (str_match(extension, extension_len, literal("cpp"))) treat_as_code = 1; + else if (str_match(extension, extension_len, literal("h"))) treat_as_code = 1; + else if (str_match(extension, extension_len, literal("c"))) treat_as_code = 1; + else if (str_match(extension, extension_len, literal("hpp"))) treat_as_code = 1; + } + + push_parameter(app, cmd_context, par_lex_as_cpp_file, treat_as_code); + push_parameter(app, cmd_context, par_wrap_lines, !treat_as_code); + push_parameter(app, cmd_context, par_key_mapid, (treat_as_code)?(my_code_map):(mapid_file)); + exec_command(cmd_context, cmdid_set_settings); +} + +CUSTOM_COMMAND_SIG(open_in_other){ + exec_command(cmd_context, cmdid_change_active_panel); + exec_command(cmd_context, cmdid_interactive_open); +} + +CUSTOM_COMMAND_SIG(open_my_files){ + // NOTE(allen|a3.1): The command cmdid_interactive_open can now open + // a file specified on the parameter stack. If the file does not exist + // cmdid_interactive_open behaves as usual. + push_parameter(app, cmd_context, par_name, literal("w:/4ed/data/test/basic.cpp")); + exec_command(cmd_context, cmdid_interactive_open); + + exec_command(cmd_context, cmdid_change_active_panel); + + char my_file[256]; + int my_file_len; + + my_file_len = sizeof("w:/4ed/data/test/basic.txt") - 1; + for (int i = 0; i < my_file_len; ++i){ + my_file[i] = ("w:/4ed/data/test/basic.txt")[i]; + } + + // NOTE(allen|a3.1): null terminators are not needed for strings. + push_parameter(app, cmd_context, par_name, my_file, my_file_len); + exec_command(cmd_context, cmdid_interactive_open); + + exec_command(cmd_context, cmdid_change_active_panel); +} + +CUSTOM_COMMAND_SIG(build_at_launch_location){ + // NOTE(allen|a3.3): An example of calling build by setting all + // parameters directly. This only works if build.bat can be called + // from the starting directory + push_parameter(app, cmd_context, par_cli_overlap_with_conflict, 1); + push_parameter(app, cmd_context, par_target_buffer_name, literal("*compilation*")); + push_parameter(app, cmd_context, par_cli_path, literal(".")); + push_parameter(app, cmd_context, par_cli_command, literal("build")); + exec_command(cmd_context, cmdid_build); +} + +CUSTOM_COMMAND_SIG(build_search){ + // NOTE(allen|a3.3): An example of traversing the filesystem through parent + // directories looking for a file, in this case a batch file to execute. + // + // + // Step 1: push_directory returns a String containing the current "hot" directory + // (whatever directory you most recently visited in the 4coder file browsing interface) + // + // Step 2: app->directory_has_file queries the file system to see if "build.bat" exists + // If it does exist several parameters are pushed: + // - par_cli_overlap_with_conflict: whether to launch this process if an existing process + // is already being used for output on the same buffer + // + // - par_target_buffer_name: the name of the buffer to fill with the output from the process + // + // - par_cli_path: sets the path from which the command is executed + // + // - par_cli_command: sets the actual command to be executed, this can be almost any command + // that you could execute through a command line interface + // + // + // To set par_cli_path: push_parameter makes a copy of the dir string on the stack + // because the string allocated by push_directory is going to change again + // To set par_cli_command: app->push_parameter does not make a copy of the dir because + // dir isn't going to change again. + // + // Step 3: If the batch file did not exist try to move to the parent directory using + // app->directory_cd. The cd function can also be used to navigate to subdirectories. + // It returns true if it can actually move in the specified direction, and false otherwise. + + int keep_going = 1; + String dir = push_directory(app, cmd_context); + while (keep_going){ + if (app->directory_has_file(dir, "build.bat")){ + push_parameter(app, cmd_context, par_cli_overlap_with_conflict, 0); + push_parameter(app, cmd_context, par_target_buffer_name, literal("*compilation*")); + push_parameter(app, cmd_context, par_cli_path, dir.str, dir.size); + + if (append(&dir, "build")){ + app->push_parameter(cmd_context, + dynamic_int(par_cli_command), + dynamic_string(dir.str, dir.size)); + exec_command(cmd_context, cmdid_build); + } + else{ + clear_parameters(cmd_context); + } + + return; + } + + if (app->directory_cd(&dir, "..") == 0){ + keep_going = 0; + } + } + + // TODO(allen): feedback message - couldn't find build.bat +} + +CUSTOM_COMMAND_SIG(write_and_auto_tab){ + exec_command(cmd_context, cmdid_write_character); + exec_command(cmd_context, cmdid_auto_tab_line_at_cursor); +} + +extern "C" GET_BINDING_DATA(get_bindings){ + Bind_Helper context_actual = begin_bind_helper(data, size); + Bind_Helper *context = &context_actual; + + // NOTE(allen|a3.1): Right now hooks have no loyalties to maps, all hooks are + // global and once set they always apply, regardless of what map is active. + set_hook(context, hook_start, my_start); + set_hook(context, hook_open_file, my_file_settings); + + begin_map(context, mapid_global); + + bind(context, 'p', MDFR_CTRL, cmdid_open_panel_vsplit); + bind(context, '-', MDFR_CTRL, cmdid_open_panel_hsplit); + bind(context, 'P', MDFR_CTRL, cmdid_close_panel); + bind(context, 'n', MDFR_CTRL, cmdid_interactive_new); + bind(context, 'o', MDFR_CTRL, cmdid_interactive_open); + bind(context, ',', MDFR_CTRL, cmdid_change_active_panel); + bind(context, 'k', MDFR_CTRL, cmdid_interactive_kill_buffer); + bind(context, 'i', MDFR_CTRL, cmdid_interactive_switch_buffer); + bind(context, 'c', MDFR_ALT, cmdid_open_color_tweaker); + bind(context, 'x', MDFR_ALT, cmdid_open_menu); + bind_me(context, 'o', MDFR_ALT, open_in_other); + + // NOTE(allen): These callbacks may not actually be useful to you, but + // go look at them and see what they do. + bind_me(context, 'M', MDFR_ALT | MDFR_CTRL, open_my_files); + bind_me(context, 'M', MDFR_ALT, build_at_launch_location); + bind_me(context, 'm', MDFR_ALT, build_search); + + end_map(context); + + + begin_map(context, my_code_map); + + // NOTE(allen|a3.1): Set this map (my_code_map == mapid_user_custom) to + // inherit from mapid_file. When searching if a key is bound + // in this map, if it is not found here it will then search mapid_file. + // + // If this is not set, it defaults to mapid_global. + inherit_map(context, mapid_file); + + // NOTE(allen|a3.1): Children can override parent's bindings. + bind(context, codes->right, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_right); + bind(context, codes->left, MDFR_CTRL, cmdid_seek_alphanumeric_or_camel_left); + + // NOTE(allen|a3.2): Specific keys can override vanilla keys, + // and write character writes whichever character corresponds + // to the key that triggered the command. + bind_me(context, '\n', MDFR_NONE, write_and_auto_tab); + bind_me(context, '}', MDFR_NONE, write_and_auto_tab); + bind_me(context, ')', MDFR_NONE, write_and_auto_tab); + bind_me(context, ']', MDFR_NONE, write_and_auto_tab); + bind_me(context, ';', MDFR_NONE, write_and_auto_tab); + + bind(context, '\t', MDFR_NONE, cmdid_auto_tab_line_at_cursor); + bind(context, '\t', MDFR_CTRL, cmdid_auto_tab_range); + bind(context, '\t', MDFR_CTRL | MDFR_SHIFT, cmdid_write_character); + + end_map(context); + + + begin_map(context, mapid_file); + + // NOTE(allen|a3.1): Binding this essentially binds all key combos that + // would normally insert a character into a buffer. + // Or apply this rule (which always works): if the code for the key + // is not in the codes struct, it is a vanilla key. + // It is possible to override this binding for individual keys. + bind_vanilla_keys(context, cmdid_write_character); + + bind(context, codes->left, MDFR_NONE, cmdid_move_left); + bind(context, codes->right, MDFR_NONE, cmdid_move_right); + bind(context, codes->del, MDFR_NONE, cmdid_delete); + bind(context, codes->back, MDFR_NONE, cmdid_backspace); + bind(context, codes->up, MDFR_NONE, cmdid_move_up); + bind(context, codes->down, MDFR_NONE, cmdid_move_down); + bind(context, codes->end, MDFR_NONE, cmdid_seek_end_of_line); + bind(context, codes->home, MDFR_NONE, cmdid_seek_beginning_of_line); + bind(context, codes->page_up, MDFR_NONE, cmdid_page_up); + bind(context, codes->page_down, MDFR_NONE, cmdid_page_down); + + bind(context, codes->right, MDFR_CTRL, cmdid_seek_whitespace_right); + bind(context, codes->left, MDFR_CTRL, cmdid_seek_whitespace_left); + bind(context, codes->up, MDFR_CTRL, cmdid_seek_whitespace_up); + bind(context, codes->down, MDFR_CTRL, cmdid_seek_whitespace_down); + + bind(context, ' ', MDFR_CTRL, cmdid_set_mark); + bind(context, 'm', MDFR_CTRL, cmdid_cursor_mark_swap); + bind(context, 'c', MDFR_CTRL, cmdid_copy); + bind(context, 'x', MDFR_CTRL, cmdid_cut); + bind(context, 'v', MDFR_CTRL, cmdid_paste); + bind(context, 'V', MDFR_CTRL, cmdid_paste_next); + bind(context, 'Z', MDFR_CTRL, cmdid_timeline_scrub); + bind(context, 'z', MDFR_CTRL, cmdid_undo); + bind(context, 'y', MDFR_CTRL, cmdid_redo); + bind(context, codes->left, MDFR_ALT, cmdid_increase_rewind_speed); + bind(context, codes->right, MDFR_ALT, cmdid_increase_fastforward_speed); + bind(context, codes->down, MDFR_ALT, cmdid_stop_rewind_fastforward); + bind(context, 'h', MDFR_CTRL, cmdid_history_backward); + bind(context, 'H', MDFR_CTRL, cmdid_history_forward); + bind(context, 'd', MDFR_CTRL, cmdid_delete_range); + bind(context, 'l', MDFR_CTRL, cmdid_toggle_line_wrap); + bind(context, 'L', MDFR_CTRL, cmdid_toggle_endline_mode); + bind(context, 'u', MDFR_CTRL, cmdid_to_uppercase); + bind(context, 'j', MDFR_CTRL, cmdid_to_lowercase); + bind(context, '?', MDFR_CTRL, cmdid_toggle_show_whitespace); + + bind(context, '~', MDFR_CTRL, cmdid_clean_all_lines); + // NOTE(allen|a3.2): These now only set the mode of the file for writing to disk + // they do no longer effect the internal representation. + bind(context, '1', MDFR_CTRL, cmdid_eol_dosify); + bind(context, '!', MDFR_CTRL, cmdid_eol_nixify); + + bind(context, 'f', MDFR_CTRL, cmdid_search); + bind(context, 'r', MDFR_CTRL, cmdid_rsearch); + bind(context, 'g', MDFR_CTRL, cmdid_goto_line); + + bind(context, 'K', MDFR_CTRL, cmdid_kill_buffer); + bind(context, 'O', MDFR_CTRL, cmdid_reopen); + bind(context, 'w', MDFR_CTRL, cmdid_interactive_save_as); + bind(context, 's', MDFR_CTRL, cmdid_save); + + end_map(context); + end_bind_helper(context); + + return context->write_total; +} + +inline void +strset_(char *dst, char *src){ + do{ + *dst++ = *src++; + }while (*src); +} + +#define strset(d,s) if (sizeof(s) <= sizeof(d)) strset_(d,s) + +extern "C" SET_EXTRA_FONT_SIG(set_extra_font){ + strset(font_out->file_name, "liberation-mono.ttf"); + strset(font_out->font_name, "BIG"); + font_out->size = 25; +} + + diff --git a/4coder_custom.h b/4coder_custom.h index 359ca5f2..f67b6623 100644 --- a/4coder_custom.h +++ b/4coder_custom.h @@ -1,337 +1,336 @@ - -#define MDFR_NONE 0 -#define MDFR_CTRL 1 -#define MDFR_ALT 2 -#define MDFR_SHIFT 4 -#define MDFR_NUMPAD 8 - -typedef unsigned char Code; - -struct Key_Codes{ - Code back; - Code up; - Code down; - Code left; - Code right; - Code del; - Code insert; - Code home; - Code end; - Code page_up; - Code page_down; - Code esc; - -#if 0 // TODO(allen): Get these working sometime - union{ - struct{ - Code f1; - Code f2; - Code f3; - Code f4; - Code f5; - Code f6; - Code f7; - Code f8; - - Code f9; - Code f10; - Code f11; - Code f12; - Code f13; - Code f14; - Code f15; - Code f16; - }; - Code f[16]; - }; -#endif -}; - -enum Command_ID{ - cmdid_null, - cmdid_write_character, - cmdid_seek_whitespace_right, - cmdid_seek_whitespace_left, - cmdid_seek_whitespace_up, - cmdid_seek_whitespace_down, - cmdid_seek_token_left, - cmdid_seek_token_right, - cmdid_seek_white_or_token_left, - cmdid_seek_white_or_token_right, - cmdid_seek_alphanumeric_left, - cmdid_seek_alphanumeric_right, - cmdid_seek_alphanumeric_or_camel_left, - cmdid_seek_alphanumeric_or_camel_right, - cmdid_search, - cmdid_rsearch, - cmdid_goto_line, - cmdid_set_mark, - cmdid_copy, - cmdid_cut, - cmdid_paste, - cmdid_paste_next, - cmdid_delete_range, - cmdid_timeline_scrub, - cmdid_undo, - cmdid_redo, - cmdid_increase_rewind_speed, - cmdid_increase_fastforward_speed, - cmdid_stop_rewind_fastforward, - cmdid_history_backward, - cmdid_history_forward, - cmdid_interactive_new, - cmdid_interactive_open, - cmdid_reopen, - cmdid_save, - cmdid_interactive_save_as, - cmdid_change_active_panel, - cmdid_interactive_switch_buffer, - cmdid_interactive_kill_buffer, - cmdid_kill_buffer, - cmdid_toggle_line_wrap, - cmdid_toggle_endline_mode, - cmdid_to_uppercase, - cmdid_to_lowercase, - cmdid_toggle_show_whitespace, - cmdid_clean_all_lines, - cmdid_eol_dosify, - cmdid_eol_nixify, - cmdid_auto_tab, - cmdid_auto_tab_range, - cmdid_auto_tab_line_at_cursor, - cmdid_auto_tab_whole_file, - cmdid_open_panel_vsplit, - cmdid_open_panel_hsplit, - cmdid_close_panel, - cmdid_move_left, - cmdid_move_right, - cmdid_delete, - cmdid_backspace, - cmdid_move_up, - cmdid_move_down, - cmdid_seek_end_of_line, - cmdid_seek_beginning_of_line, - cmdid_page_up, - cmdid_page_down, - cmdid_open_color_tweaker, - cmdid_close_minor_view, - cmdid_cursor_mark_swap, - cmdid_open_menu, - cmdid_set_settings, - cmdid_build, - // - cmdid_count -}; - -enum Param_ID{ - par_name, - par_lex_as_cpp_file, - par_wrap_lines, - par_key_mapid, - par_target_buffer_name, - par_cli_path, - par_cli_command, - par_cli_overlap_with_conflict, - par_cli_always_bind_to_view, - // never below this - par_type_count -}; - -enum Hook_ID{ - hook_start, - hook_open_file, - // never below this - hook_type_count -}; - -enum Dynamic_Type{ - dynamic_type_int, - dynamic_type_string, - // never below this - dynamic_type_count -}; - -struct Dynamic{ - int type; - union{ - struct{ - int str_len; - char *str_value; - }; - int int_value; - }; -}; - -inline Dynamic -dynamic_int(int x){ - Dynamic result; - result.type = dynamic_type_int; - result.int_value = x; - return result; -} - -inline Dynamic -dynamic_string(const char *string, int len){ - Dynamic result; - result.type = dynamic_type_string; - result.str_len = len; - result.str_value = (char*)(string); - return result; -} - -inline int -dynamic_to_int(Dynamic *dynamic){ - int result = 0; - if (dynamic->type == dynamic_type_int){ - result = dynamic->int_value; - } - return result; -} - -inline char* -dynamic_to_string(Dynamic *dynamic, int *len){ - char *result = 0; - if (dynamic->type == dynamic_type_string){ - result = dynamic->str_value; - *len = dynamic->str_len; - } - return result; -} - -inline int -dynamic_to_bool(Dynamic *dynamic){ - int result = 0; - if (dynamic->type == dynamic_type_int){ - result = (dynamic->int_value != 0); - } - else{ - result = 1; - } - return result; -} - -struct Extra_Font{ - char file_name[256]; - char font_name[24]; - int size; -}; - -struct Buffer_Summary{ - // NOTE(allen): None of these members nor any of the data pointed to - // by these members should be modified. - int file_id; - - int size; - - int file_name_len; - int buffer_name_len; - const char *file_name; - const char *buffer_name; - - int file_cursor_pos; - int is_lexed; - int map_id; -}; - -#ifndef FRED_STRING_STRUCT -#define FRED_STRING_STRUCT -struct String{ - char *str; - int size; - int memory_size; -}; -#endif - -#define GET_BINDING_DATA(name) int name(void *data, int size, Key_Codes *codes) -#define SET_EXTRA_FONT_SIG(name) void name(Extra_Font *font_out) -#define CUSTOM_COMMAND_SIG(name) void name(void *cmd_context, struct Application_Links *app) -#define HOOK_SIG(name) void name(void *cmd_context, struct Application_Links *app) - -extern "C"{ - typedef CUSTOM_COMMAND_SIG(Custom_Command_Function); - typedef GET_BINDING_DATA(Get_Binding_Data_Function); - typedef SET_EXTRA_FONT_SIG(Set_Extra_Font_Function); - typedef HOOK_SIG(Hook_Function); -} - -#define PUSH_PARAMETER_SIG(name) void name(void *cmd_context, Dynamic param, Dynamic value) -#define PUSH_MEMORY_SIG(name) char* name(void *cmd_context, int len) -#define EXECUTE_COMMAND_SIG(name) void name(void *cmd_context, int command_id) -#define CLEAR_PARAMETERS_SIG(name) void name(void *cmd_context) -#define GET_ACTIVE_BUFFER_SIG(name) Buffer_Summary name(void *cmd_context) -#define DIRECTORY_GET_HOT_SIG(name) int name(void *cmd_context, char *buffer, int max) -#define DIRECTORY_HAS_FILE_SIG(name) int name(String dir, char *filename) -#define DIRECTORY_CD_SIG(name) int name(String *dir, char *rel_path) - -extern "C"{ - typedef EXECUTE_COMMAND_SIG(Exec_Command_Function); - typedef PUSH_PARAMETER_SIG(Push_Parameter_Function); - typedef PUSH_MEMORY_SIG(Push_Memory_Function); - typedef CLEAR_PARAMETERS_SIG(Clear_Parameters_Function); - typedef GET_ACTIVE_BUFFER_SIG(Get_Active_Buffer_Function); - typedef DIRECTORY_GET_HOT_SIG(Directory_Get_Hot); - typedef DIRECTORY_HAS_FILE_SIG(Directory_Has_File); - typedef DIRECTORY_CD_SIG(Directory_CD); -} - -struct Application_Links{ - Exec_Command_Function *exec_command_keep_stack; - Push_Parameter_Function *push_parameter; - Push_Memory_Function *push_memory; - Clear_Parameters_Function *clear_parameters; - Get_Active_Buffer_Function *get_active_buffer; - Directory_Get_Hot *directory_get_hot; - Directory_Has_File *directory_has_file; - Directory_CD *directory_cd; -}; - -struct Custom_API{ - Get_Binding_Data_Function *get_bindings; - Set_Extra_Font_Function *set_extra_font; -}; - -// NOTE(allen): definitions for the buffer that communicates to 4ed.exe - -enum Binding_Unit_Type{ - unit_header, - unit_map_begin, - unit_binding, - unit_callback, - unit_inherit, - unit_hook -}; - -enum Map_ID{ - mapid_global, - mapid_file, - // NOTE(allen): mapid_nomap will remain empty even if you attempt to fill it - // it is for setting a map's parent to nothing - mapid_nomap, - mapid_user_custom = 100 -}; - -struct Binding_Unit{ - Binding_Unit_Type type; - union{ - struct{ int total_size; int user_map_count; int error; } header; - - struct{ int mapid; int bind_count; } map_begin; - struct{ int mapid; } map_inherit; - struct{ - short code; - unsigned char modifiers; - int command_id; - } binding; - struct{ - short code; - unsigned char modifiers; - Custom_Command_Function *func; - } callback; - struct{ - int hook_id; - Custom_Command_Function *func; - } hook; - }; -}; - - + +#define MDFR_NONE 0 +#define MDFR_CTRL 1 +#define MDFR_ALT 2 +#define MDFR_SHIFT 4 +#define MDFR_NUMPAD 8 + +typedef unsigned char Code; + +struct Key_Codes{ + Code back; + Code up; + Code down; + Code left; + Code right; + Code del; + Code insert; + Code home; + Code end; + Code page_up; + Code page_down; + Code esc; + +#if 0 // TODO(allen): Get these working sometime + union{ + struct{ + Code f1; + Code f2; + Code f3; + Code f4; + Code f5; + Code f6; + Code f7; + Code f8; + + Code f9; + Code f10; + Code f11; + Code f12; + Code f13; + Code f14; + Code f15; + Code f16; + }; + Code f[16]; + }; +#endif +}; + +enum Command_ID{ + cmdid_null, + cmdid_write_character, + cmdid_seek_whitespace_right, + cmdid_seek_whitespace_left, + cmdid_seek_whitespace_up, + cmdid_seek_whitespace_down, + cmdid_seek_token_left, + cmdid_seek_token_right, + cmdid_seek_white_or_token_left, + cmdid_seek_white_or_token_right, + cmdid_seek_alphanumeric_left, + cmdid_seek_alphanumeric_right, + cmdid_seek_alphanumeric_or_camel_left, + cmdid_seek_alphanumeric_or_camel_right, + cmdid_search, + cmdid_rsearch, + cmdid_goto_line, + cmdid_set_mark, + cmdid_copy, + cmdid_cut, + cmdid_paste, + cmdid_paste_next, + cmdid_delete_range, + cmdid_timeline_scrub, + cmdid_undo, + cmdid_redo, + cmdid_increase_rewind_speed, + cmdid_increase_fastforward_speed, + cmdid_stop_rewind_fastforward, + cmdid_history_backward, + cmdid_history_forward, + cmdid_interactive_new, + cmdid_interactive_open, + cmdid_reopen, + cmdid_save, + cmdid_interactive_save_as, + cmdid_change_active_panel, + cmdid_interactive_switch_buffer, + cmdid_interactive_kill_buffer, + cmdid_kill_buffer, + cmdid_toggle_line_wrap, + cmdid_toggle_endline_mode, + cmdid_to_uppercase, + cmdid_to_lowercase, + cmdid_toggle_show_whitespace, + cmdid_clean_all_lines, + cmdid_eol_dosify, + cmdid_eol_nixify, + cmdid_auto_tab, + cmdid_auto_tab_range, + cmdid_auto_tab_line_at_cursor, + cmdid_auto_tab_whole_file, + cmdid_open_panel_vsplit, + cmdid_open_panel_hsplit, + cmdid_close_panel, + cmdid_move_left, + cmdid_move_right, + cmdid_delete, + cmdid_backspace, + cmdid_move_up, + cmdid_move_down, + cmdid_seek_end_of_line, + cmdid_seek_beginning_of_line, + cmdid_page_up, + cmdid_page_down, + cmdid_open_color_tweaker, + cmdid_close_minor_view, + cmdid_cursor_mark_swap, + cmdid_open_menu, + cmdid_set_settings, + cmdid_build, + // + cmdid_count +}; + +enum Param_ID{ + par_name, + par_lex_as_cpp_file, + par_wrap_lines, + par_key_mapid, + par_target_buffer_name, + par_cli_path, + par_cli_command, + par_cli_overlap_with_conflict, + par_cli_always_bind_to_view, + // never below this + par_type_count +}; + +enum Hook_ID{ + hook_start, + hook_open_file, + // never below this + hook_type_count +}; + +enum Dynamic_Type{ + dynamic_type_int, + dynamic_type_string, + // never below this + dynamic_type_count +}; + +struct Dynamic{ + int type; + union{ + struct{ + int str_len; + char *str_value; + }; + int int_value; + }; +}; + +inline Dynamic +dynamic_int(int x){ + Dynamic result; + result.type = dynamic_type_int; + result.int_value = x; + return result; +} + +inline Dynamic +dynamic_string(const char *string, int len){ + Dynamic result; + result.type = dynamic_type_string; + result.str_len = len; + result.str_value = (char*)(string); + return result; +} + +inline int +dynamic_to_int(Dynamic *dynamic){ + int result = 0; + if (dynamic->type == dynamic_type_int){ + result = dynamic->int_value; + } + return result; +} + +inline char* +dynamic_to_string(Dynamic *dynamic, int *len){ + char *result = 0; + if (dynamic->type == dynamic_type_string){ + result = dynamic->str_value; + *len = dynamic->str_len; + } + return result; +} + +inline int +dynamic_to_bool(Dynamic *dynamic){ + int result = 0; + if (dynamic->type == dynamic_type_int){ + result = (dynamic->int_value != 0); + } + else{ + result = 1; + } + return result; +} + +struct Extra_Font{ + char file_name[256]; + char font_name[24]; + int size; +}; + +struct Buffer_Summary{ + // NOTE(allen): None of these members nor any of the data pointed to + // by these members should be modified. + int file_id; + + int size; + + int file_name_len; + int buffer_name_len; + const char *file_name; + const char *buffer_name; + + int file_cursor_pos; + int is_lexed; + int map_id; +}; + +#ifndef FRED_STRING_STRUCT +#define FRED_STRING_STRUCT +struct String{ + char *str; + int size; + int memory_size; +}; +#endif + +#define GET_BINDING_DATA(name) int name(void *data, int size, Key_Codes *codes) +#define SET_EXTRA_FONT_SIG(name) void name(Extra_Font *font_out) +#define CUSTOM_COMMAND_SIG(name) void name(void *cmd_context, struct Application_Links *app) +#define HOOK_SIG(name) void name(void *cmd_context, struct Application_Links *app) + +extern "C"{ + typedef CUSTOM_COMMAND_SIG(Custom_Command_Function); + typedef GET_BINDING_DATA(Get_Binding_Data_Function); + typedef SET_EXTRA_FONT_SIG(Set_Extra_Font_Function); + typedef HOOK_SIG(Hook_Function); +} + +#define PUSH_PARAMETER_SIG(name) void name(void *cmd_context, Dynamic param, Dynamic value) +#define PUSH_MEMORY_SIG(name) char* name(void *cmd_context, int len) +#define EXECUTE_COMMAND_SIG(name) void name(void *cmd_context, int command_id) +#define CLEAR_PARAMETERS_SIG(name) void name(void *cmd_context) +#define GET_ACTIVE_BUFFER_SIG(name) Buffer_Summary name(void *cmd_context) +#define DIRECTORY_GET_HOT_SIG(name) int name(void *cmd_context, char *buffer, int max) +#define DIRECTORY_HAS_FILE_SIG(name) int name(String dir, char *filename) +#define DIRECTORY_CD_SIG(name) int name(String *dir, char *rel_path) + +extern "C"{ + typedef EXECUTE_COMMAND_SIG(Exec_Command_Function); + typedef PUSH_PARAMETER_SIG(Push_Parameter_Function); + typedef PUSH_MEMORY_SIG(Push_Memory_Function); + typedef CLEAR_PARAMETERS_SIG(Clear_Parameters_Function); + typedef GET_ACTIVE_BUFFER_SIG(Get_Active_Buffer_Function); + typedef DIRECTORY_GET_HOT_SIG(Directory_Get_Hot); + typedef DIRECTORY_HAS_FILE_SIG(Directory_Has_File); + typedef DIRECTORY_CD_SIG(Directory_CD); +} + +struct Application_Links{ + Exec_Command_Function *exec_command_keep_stack; + Push_Parameter_Function *push_parameter; + Push_Memory_Function *push_memory; + Clear_Parameters_Function *clear_parameters; + Get_Active_Buffer_Function *get_active_buffer; + Directory_Get_Hot *directory_get_hot; + Directory_Has_File *directory_has_file; + Directory_CD *directory_cd; +}; + +struct Custom_API{ + Get_Binding_Data_Function *get_bindings; +}; + +// NOTE(allen): definitions for the buffer that communicates to 4ed.exe + +enum Binding_Unit_Type{ + unit_header, + unit_map_begin, + unit_binding, + unit_callback, + unit_inherit, + unit_hook +}; + +enum Map_ID{ + mapid_global = (1 << 24), + mapid_file, + // NOTE(allen): mapid_nomap will remain empty even if you attempt to fill it + // it is for setting a map's parent to nothing, in cases where you don't want + // to inherit from global (which is the default). + mapid_nomap +}; + +struct Binding_Unit{ + Binding_Unit_Type type; + union{ + struct{ int total_size; int user_map_count; int error; } header; + + struct{ int mapid; int bind_count; } map_begin; + struct{ int mapid; } map_inherit; + struct{ + short code; + unsigned char modifiers; + int command_id; + } binding; + struct{ + short code; + unsigned char modifiers; + Custom_Command_Function *func; + } callback; + struct{ + int hook_id; + Custom_Command_Function *func; + } hook; + }; +}; + + diff --git a/4coder_helper.h b/4coder_helper.h index 42e2ed69..c1658817 100644 --- a/4coder_helper.h +++ b/4coder_helper.h @@ -1,252 +1,252 @@ -/* - * Bind helper struct and functions - */ - -struct Bind_Helper{ - Binding_Unit *cursor, *start, *end; - Binding_Unit *header, *group; - int write_total; - int error; -}; - -#define BH_ERR_NONE 0 -#define BH_ERR_MISSING_END 1 -#define BH_ERR_MISSING_BEGIN 2 -#define BH_ERR_OUT_OF_MEMORY 3 - -inline void -copy(char *dest, const char *src, int len){ - for (int i = 0; i < len; ++i){ - *dest++ = *src++; - } -} - -inline Binding_Unit* -write_unit(Bind_Helper *helper, Binding_Unit unit){ - Binding_Unit *p = 0; - helper->write_total += sizeof(*p); - if (helper->error == 0 && helper->cursor != helper->end){ - p = helper->cursor++; - *p = unit; - } - return p; -} - -inline char* -write_inline_string(Bind_Helper *helper, char *value, int len){ - char *dest = 0; - helper->write_total += len; - if (helper->error == 0){ - dest = (char*)helper->cursor; - int cursor_advance = len + sizeof(*helper->cursor) - 1; - cursor_advance /= sizeof(*helper->cursor); - cursor_advance *= sizeof(*helper->cursor); - helper->cursor += cursor_advance; - if (helper->cursor < helper->end){ - copy(dest, value, len); - } - else{ - helper->error = BH_ERR_OUT_OF_MEMORY; - } - } - return dest; -} - -inline Bind_Helper -begin_bind_helper(void *data, int size){ - Bind_Helper result; - - result.header = 0; - result.group = 0; - result.write_total = 0; - result.error = 0; - - result.cursor = (Binding_Unit*)data; - result.start = result.cursor; - result.end = result.start + size / sizeof(*result.cursor); - - Binding_Unit unit; - unit.type = unit_header; - unit.header.total_size = sizeof(*result.header); - result.header = write_unit(&result, unit); - result.header->header.user_map_count = 0; - - return result; -} - -inline void -begin_map(Bind_Helper *helper, int mapid){ - if (helper->group != 0 && helper->error == 0) helper->error = BH_ERR_MISSING_END; - if (!helper->error && mapid >= mapid_user_custom) ++helper->header->header.user_map_count; - - Binding_Unit unit; - unit.type = unit_map_begin; - unit.map_begin.mapid = mapid; - helper->group = write_unit(helper, unit); - helper->group->map_begin.bind_count = 0; -} - -inline void -end_map(Bind_Helper *helper){ - if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; - helper->group = 0; -} - -struct Bind_Target{ - short code; - unsigned char modifiers; -}; - -inline Bind_Target -tkey(short code, unsigned char modifiers){ - Bind_Target target; - target.code = code; - target.modifiers = modifiers; - return target; -} - -inline void -bind(Bind_Helper *helper, Bind_Target target, int cmdid){ - if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; - if (!helper->error) ++helper->group->map_begin.bind_count; - - Binding_Unit unit; - unit.type = unit_binding; - unit.binding.command_id = cmdid; - unit.binding.code = target.code; - unit.binding.modifiers = target.modifiers; - - write_unit(helper, unit); -} - -inline void -bind_me(Bind_Helper *helper, Bind_Target target, Custom_Command_Function *func){ - if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; - if (!helper->error) ++helper->group->map_begin.bind_count; - - Binding_Unit unit; - unit.type = unit_callback; - unit.callback.func = func; - unit.callback.code = target.code; - unit.callback.modifiers = target.modifiers; - - write_unit(helper, unit); -} - -inline void -bind(Bind_Helper *helper, short code, unsigned char modifiers, int cmdid){ - Bind_Target target; - target = tkey(code, modifiers); - bind(helper, target, cmdid); -} - -inline void -bind_me(Bind_Helper *helper, short code, unsigned char modifiers, Custom_Command_Function *func){ - Bind_Target target; - target = tkey(code, modifiers); - bind_me(helper, target, func); -} - -inline void -bind_vanilla_keys(Bind_Helper *helper, int cmdid){ - bind(helper, 0, 0, cmdid); -} - -inline void -bind_me_vanilla_keys(Bind_Helper *helper, Custom_Command_Function *func){ - bind_me(helper, 0, 0, func); -} - -inline void -bind_vanilla_keys(Bind_Helper *helper, unsigned char modifiers, int cmdid){ - bind(helper, 0, modifiers, cmdid); -} - -inline void -bind_me_vanilla_keys(Bind_Helper *helper, unsigned char modifiers, Custom_Command_Function *func){ - bind_me(helper, 0, modifiers, func); -} - -inline void -inherit_map(Bind_Helper *helper, int mapid){ - if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; - if (!helper->error && mapid >= mapid_user_custom) ++helper->header->header.user_map_count; - - Binding_Unit unit; - unit.type = unit_inherit; - unit.map_inherit.mapid = mapid; - - write_unit(helper, unit); -} - -inline void -set_hook(Bind_Helper *helper, int hook_id, Custom_Command_Function *func){ - Binding_Unit unit; - unit.type = unit_hook; - unit.hook.hook_id = hook_id; - unit.hook.func = func; - - write_unit(helper, unit); -} - -inline void -end_bind_helper(Bind_Helper *helper){ - if (helper->header){ - helper->header->header.total_size = (int)(helper->cursor - helper->start); - helper->header->header.error = helper->error; - } -} - -// NOTE(allen): Useful functions and overloads on app links -inline void -push_parameter(Application_Links *app, void *cmd_context, int param, int value){ - app->push_parameter(cmd_context, dynamic_int(param), dynamic_int(value)); -} - -inline void -push_parameter(Application_Links *app, void *cmd_context, int param, const char *value, int value_len){ - char *value_copy = app->push_memory(cmd_context, value_len+1); - copy(value_copy, value, value_len); - value_copy[value_len] = 0; - app->push_parameter(cmd_context, dynamic_int(param), dynamic_string(value_copy, value_len)); -} - -inline void -push_parameter(Application_Links *app, void *cmd_context, const char *param, int param_len, int value){ - char *param_copy = app->push_memory(cmd_context, param_len+1); - copy(param_copy, param, param_len); - param_copy[param_len] = 0; - app->push_parameter(cmd_context, dynamic_string(param_copy, param_len), dynamic_int(value)); -} - -inline void -push_parameter(Application_Links *app, void *cmd_context, const char *param, int param_len, const char *value, int value_len){ - char *param_copy = app->push_memory(cmd_context, param_len+1); - char *value_copy = app->push_memory(cmd_context, value_len+1); - copy(param_copy, param, param_len); - copy(value_copy, value, value_len); - value_copy[value_len] = 0; - param_copy[param_len] = 0; - - app->push_parameter(cmd_context, dynamic_string(param_copy, param_len), dynamic_string(value_copy, value_len)); -} - -inline String -push_directory(Application_Links *app, void *cmd_context){ - String result; - result.memory_size = 512; - result.str = app->push_memory(cmd_context, result.memory_size); - result.size = app->directory_get_hot(cmd_context, result.str, result.memory_size); - return(result); -} - -#define dir_string(d) ((d).str), ((d).size) - -#define exec_command_keep_stack app->exec_command_keep_stack -#define clear_parameters app->clear_parameters -#define get_active_buffer app->get_active_buffer - -#define exec_command(cmd_context, id) \ - exec_command_keep_stack(cmd_context, id); \ - clear_parameters(cmd_context) - +/* + * Bind helper struct and functions + */ + +struct Bind_Helper{ + Binding_Unit *cursor, *start, *end; + Binding_Unit *header, *group; + int write_total; + int error; +}; + +#define BH_ERR_NONE 0 +#define BH_ERR_MISSING_END 1 +#define BH_ERR_MISSING_BEGIN 2 +#define BH_ERR_OUT_OF_MEMORY 3 + +inline void +copy(char *dest, const char *src, int len){ + for (int i = 0; i < len; ++i){ + *dest++ = *src++; + } +} + +inline Binding_Unit* +write_unit(Bind_Helper *helper, Binding_Unit unit){ + Binding_Unit *p = 0; + helper->write_total += sizeof(*p); + if (helper->error == 0 && helper->cursor != helper->end){ + p = helper->cursor++; + *p = unit; + } + return p; +} + +inline char* +write_inline_string(Bind_Helper *helper, char *value, int len){ + char *dest = 0; + helper->write_total += len; + if (helper->error == 0){ + dest = (char*)helper->cursor; + int cursor_advance = len + sizeof(*helper->cursor) - 1; + cursor_advance /= sizeof(*helper->cursor); + cursor_advance *= sizeof(*helper->cursor); + helper->cursor += cursor_advance; + if (helper->cursor < helper->end){ + copy(dest, value, len); + } + else{ + helper->error = BH_ERR_OUT_OF_MEMORY; + } + } + return dest; +} + +inline Bind_Helper +begin_bind_helper(void *data, int size){ + Bind_Helper result; + + result.header = 0; + result.group = 0; + result.write_total = 0; + result.error = 0; + + result.cursor = (Binding_Unit*)data; + result.start = result.cursor; + result.end = result.start + size / sizeof(*result.cursor); + + Binding_Unit unit; + unit.type = unit_header; + unit.header.total_size = sizeof(*result.header); + result.header = write_unit(&result, unit); + result.header->header.user_map_count = 0; + + return result; +} + +inline void +begin_map(Bind_Helper *helper, int mapid){ + if (helper->group != 0 && helper->error == 0) helper->error = BH_ERR_MISSING_END; + if (!helper->error && mapid < mapid_global) ++helper->header->header.user_map_count; + + Binding_Unit unit; + unit.type = unit_map_begin; + unit.map_begin.mapid = mapid; + helper->group = write_unit(helper, unit); + helper->group->map_begin.bind_count = 0; +} + +inline void +end_map(Bind_Helper *helper){ + if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; + helper->group = 0; +} + +struct Bind_Target{ + short code; + unsigned char modifiers; +}; + +inline Bind_Target +tkey(short code, unsigned char modifiers){ + Bind_Target target; + target.code = code; + target.modifiers = modifiers; + return target; +} + +inline void +bind(Bind_Helper *helper, Bind_Target target, int cmdid){ + if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; + if (!helper->error) ++helper->group->map_begin.bind_count; + + Binding_Unit unit; + unit.type = unit_binding; + unit.binding.command_id = cmdid; + unit.binding.code = target.code; + unit.binding.modifiers = target.modifiers; + + write_unit(helper, unit); +} + +inline void +bind_me(Bind_Helper *helper, Bind_Target target, Custom_Command_Function *func){ + if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; + if (!helper->error) ++helper->group->map_begin.bind_count; + + Binding_Unit unit; + unit.type = unit_callback; + unit.callback.func = func; + unit.callback.code = target.code; + unit.callback.modifiers = target.modifiers; + + write_unit(helper, unit); +} + +inline void +bind(Bind_Helper *helper, short code, unsigned char modifiers, int cmdid){ + Bind_Target target; + target = tkey(code, modifiers); + bind(helper, target, cmdid); +} + +inline void +bind_me(Bind_Helper *helper, short code, unsigned char modifiers, Custom_Command_Function *func){ + Bind_Target target; + target = tkey(code, modifiers); + bind_me(helper, target, func); +} + +inline void +bind_vanilla_keys(Bind_Helper *helper, int cmdid){ + bind(helper, 0, 0, cmdid); +} + +inline void +bind_me_vanilla_keys(Bind_Helper *helper, Custom_Command_Function *func){ + bind_me(helper, 0, 0, func); +} + +inline void +bind_vanilla_keys(Bind_Helper *helper, unsigned char modifiers, int cmdid){ + bind(helper, 0, modifiers, cmdid); +} + +inline void +bind_me_vanilla_keys(Bind_Helper *helper, unsigned char modifiers, Custom_Command_Function *func){ + bind_me(helper, 0, modifiers, func); +} + +inline void +inherit_map(Bind_Helper *helper, int mapid){ + if (helper->group == 0 && helper->error == 0) helper->error = BH_ERR_MISSING_BEGIN; + if (!helper->error && mapid < mapid_global) ++helper->header->header.user_map_count; + + Binding_Unit unit; + unit.type = unit_inherit; + unit.map_inherit.mapid = mapid; + + write_unit(helper, unit); +} + +inline void +set_hook(Bind_Helper *helper, int hook_id, Custom_Command_Function *func){ + Binding_Unit unit; + unit.type = unit_hook; + unit.hook.hook_id = hook_id; + unit.hook.func = func; + + write_unit(helper, unit); +} + +inline void +end_bind_helper(Bind_Helper *helper){ + if (helper->header){ + helper->header->header.total_size = (int)(helper->cursor - helper->start); + helper->header->header.error = helper->error; + } +} + +// NOTE(allen): Useful functions and overloads on app links +inline void +push_parameter(Application_Links *app, void *cmd_context, int param, int value){ + app->push_parameter(cmd_context, dynamic_int(param), dynamic_int(value)); +} + +inline void +push_parameter(Application_Links *app, void *cmd_context, int param, const char *value, int value_len){ + char *value_copy = app->push_memory(cmd_context, value_len+1); + copy(value_copy, value, value_len); + value_copy[value_len] = 0; + app->push_parameter(cmd_context, dynamic_int(param), dynamic_string(value_copy, value_len)); +} + +inline void +push_parameter(Application_Links *app, void *cmd_context, const char *param, int param_len, int value){ + char *param_copy = app->push_memory(cmd_context, param_len+1); + copy(param_copy, param, param_len); + param_copy[param_len] = 0; + app->push_parameter(cmd_context, dynamic_string(param_copy, param_len), dynamic_int(value)); +} + +inline void +push_parameter(Application_Links *app, void *cmd_context, const char *param, int param_len, const char *value, int value_len){ + char *param_copy = app->push_memory(cmd_context, param_len+1); + char *value_copy = app->push_memory(cmd_context, value_len+1); + copy(param_copy, param, param_len); + copy(value_copy, value, value_len); + value_copy[value_len] = 0; + param_copy[param_len] = 0; + + app->push_parameter(cmd_context, dynamic_string(param_copy, param_len), dynamic_string(value_copy, value_len)); +} + +inline String +push_directory(Application_Links *app, void *cmd_context){ + String result; + result.memory_size = 512; + result.str = app->push_memory(cmd_context, result.memory_size); + result.size = app->directory_get_hot(cmd_context, result.str, result.memory_size); + return(result); +} + +#define dir_string(d) ((d).str), ((d).size) + +#define exec_command_keep_stack app->exec_command_keep_stack +#define clear_parameters app->clear_parameters +#define get_active_buffer app->get_active_buffer + +#define exec_command(cmd_context, id) \ + exec_command_keep_stack(cmd_context, id); \ + clear_parameters(cmd_context) + diff --git a/4coder_string.h b/4coder_string.h index 6f6f7b30..868b6471 100644 --- a/4coder_string.h +++ b/4coder_string.h @@ -1,1166 +1,1166 @@ -/* "4cpp" Open C++ Parser v0.1: String - no warranty implied; use at your own risk - -NOTES ON USE: - OPTIONS: - Set options by defining macros before including this file - - FCPP_STRING_IMPLEMENTATION - causes this file to output function implementations - - this option is unset after use so that future includes of this file - in the same unit do not continue to output implementations - - FCPP_LINK - defines linkage of non-inline functions, defaults to static - FCPP_EXTERN changes FCPP_LINK default to extern, this option is ignored if FCPP_LINK is defined - - include the file "4cpp_clear_config.h" if yo want to undefine all options for some reason - - HIDDEN DEPENDENCIES: - none - */ - -// TOP -// TODO(allen): -// - comments -// - memcpy / memmove replacements (different file for optimization options?) -// - -#include "4coder_config.h" - -#ifndef FCPP_STRING_INC -#define FCPP_STRING_INC - -#ifndef FRED_STRING_STRUCT -#define FRED_STRING_STRUCT -struct String{ - char *str; - int size; - int memory_size; -}; -#endif - -inline bool char_not_slash(char c) { return (c != '\\' && c != '/'); } -inline bool char_is_slash(char c) { return (c == '\\' || c == '/'); } - -inline char char_to_upper(char c) { return (c >= 'a' && c <= 'z') ? c + (char)('A' - 'a') : c; } -inline char char_to_lower(char c) { return (c >= 'A' && c <= 'Z') ? c - (char)('A' - 'a') : c; } - -inline bool char_is_whitespace(char c) { return (c == ' ' || c == '\n' || c == '\r' || c == '\t'); } -inline bool char_is_white_not_r(char c) { return (c == ' ' || c == '\n' || c == '\t'); } -inline bool char_is_lower(char c) { return (c >= 'a' && c <= 'z'); } -inline bool char_is_upper(char c) { return (c >= 'A' && c <= 'Z'); } -inline bool char_is_alpha(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); } -inline bool char_is_alpha_true(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); } -inline bool char_is_numeric(char c) { return (c >= '0' && c <= '9'); } -inline bool char_is_alpha_numeric_true(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'); } -inline bool char_is_alpha_numeric(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_'); } -inline bool char_is_hex(char c) { return c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'; } -inline bool char_is_basic(char c) { return c >= ' ' && c <= '~'; } - -inline String make_string(char *s, int size, int mem_size); -inline String make_string(char *s, int size); - -#define make_lit_string(str) (make_string((char*)(str), sizeof(str)-1, sizeof(str))) -#define make_fixed_width_string(str) (make_string((char*)(str), 0, sizeof(str))) - -#define expand_str(s) ((s).str), ((s).size) - -inline String make_string_slowly(char *s); -inline char* make_c_str(String s); - -inline String substr(String str, int start); -inline String substr(String str, int start, int size); -inline String substr_slowly(char *s, int start); -inline String substr(char *s, int start, int size); -inline String tailstr(String s); - - -FCPP_LINK int str_size(char *s); - -FCPP_LINK bool match(char *a, char *b); -FCPP_LINK bool match(String a, char *b); -inline bool match(char *a, String b) { return match(b,a); } -FCPP_LINK bool match(String a, String b); - -FCPP_LINK bool match_part(char *a, char *b, int *len); -FCPP_LINK bool match_part(String a, char *b, int *len); -inline bool match_part(char *a, char *b) { int x; return match_part(a,b,&x); } -inline bool match_part(String a, char *b) { int x; return match_part(a,b,&x); } -FCPP_LINK bool match_part(char *a, String b); -FCPP_LINK bool match_part(String a, String b); - -FCPP_LINK bool match_unsensitive(char *a, char *b); -FCPP_LINK bool match_unsensitive(String a, char *b); -inline bool match_unsensitive(char *a, String b) { return match_unsensitive(b,a); } -FCPP_LINK bool match_unsensitive(String a, String b); - -FCPP_LINK bool match_part_unsensitive(char *a, char *b, int *len); -FCPP_LINK bool match_part_unsensitive(String a, char *b, int *len); -inline bool match_part_unsensitive(char *a, char *b) { int x; return match_part(a,b,&x); } -inline bool match_part_unsensitive(String a, char *b) { int x; return match_part(a,b,&x); } -FCPP_LINK bool match_part_unsensitive(char *a, String b); -FCPP_LINK bool match_part_unsensitive(String a, String b); - -FCPP_LINK int find(char *s, int start, char c); -FCPP_LINK int find(String s, int start, char c); -FCPP_LINK int find(char *s, int start, char *c); -FCPP_LINK int find(String s, int start, char *c); - -FCPP_LINK int find_substr(char *s, int start, String seek); -FCPP_LINK int find_substr(String s, int start, String seek); -FCPP_LINK int rfind_substr(String s, int start, String seek); - -FCPP_LINK int find_substr_unsensitive(char *s, int start, String seek); -FCPP_LINK int find_substr_unsensitive(String s, int start, String seek); - -inline bool has_substr(char *s, String seek) { return (s[find_substr(s, 0, seek)] != 0); } -inline bool has_substr(String s, String seek) { return (find_substr(s, 0, seek) < s.size); } - -inline bool has_substr_unsensitive(char *s, String seek) { return (s[find_substr_unsensitive(s, 0, seek)] != 0); } -inline bool has_substr_unsensitive(String s, String seek) { return (find_substr_unsensitive(s, 0, seek) < s.size); } - -FCPP_LINK int int_to_str_size(int x); -FCPP_LINK int int_to_str(int x, char *s_out); -FCPP_LINK bool int_to_str(int x, String *s_out); -FCPP_LINK bool append_int_to_str(int x, String *s_out); - -FCPP_LINK int str_to_int(char *s); -FCPP_LINK int str_to_int(String s); -FCPP_LINK int hexchar_to_int(char c); -FCPP_LINK int int_to_hexchar(char c); -FCPP_LINK int hexstr_to_int(String s); - -FCPP_LINK int copy_fast_unsafe(char *dest, char *src); -FCPP_LINK void copy_fast_unsafe(char *dest, String src); -FCPP_LINK bool copy_checked(String *dest, String src); -FCPP_LINK bool copy_partial(String *dest, char *src); -FCPP_LINK bool copy_partial(String *dest, String src); - -inline int copy(char *dest, char *src) { return copy_fast_unsafe(dest, src); } -inline void copy(String *dest, String src) { copy_checked(dest, src); } -inline void copy(String *dest, char *src) { copy_partial(dest, src); } - -FCPP_LINK bool append_checked(String *dest, String src); -FCPP_LINK bool append_partial(String *dest, char *src); -FCPP_LINK bool append_partial(String *dest, String src); - -FCPP_LINK bool append(String *dest, char c); -inline bool append(String *dest, String src) { return append_partial(dest, src); } -inline bool append(String *dest, char *src) { return append_partial(dest, src); } -inline bool terminate_with_null(String *str){ - bool result; - if (str->size < str->memory_size){ - str->str[str->size] = 0; - result = 1; - } - else{ - str->str[str->size-1] = 0; - result = 0; - } - return result; -} - -FCPP_LINK int compare(char *a, char *b); -FCPP_LINK int compare(String a, char *b); -inline int compare(char *a, String b) { return -compare(b,a); } -FCPP_LINK int compare(String a, String b); - -FCPP_LINK int reverse_seek_slash(String str); -FCPP_LINK int reverse_seek_slash(String str, int start_pos); -inline bool get_front_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, reverse_seek_slash(dir) + 1)); } -inline bool get_path_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, 0, reverse_seek_slash(dir) + 1)); } -FCPP_LINK bool set_last_folder(String *dir, char *folder_name); -FCPP_LINK bool set_last_folder(String *dir, String folder_name); -FCPP_LINK String file_extension(String str); -FCPP_LINK String file_extension_slowly(char *str); -FCPP_LINK bool remove_last_folder(String *str); - -inline String make_string(char *str, int size, int mem_size){ - String result; - result.str = str; - result.size = size; - result.memory_size = mem_size; - return result; -} - -inline String -make_string(char *str, int size){ - String result; - result.str = str; - result.size = size; - result.memory_size = size; - return result; -} - -inline String -make_string_slowly(char *str){ - String result; - result.str = str; - result.size = str_size(str); - result.memory_size = result.size; - return result; -} - -inline char* -make_c_str(String str){ - if (str.size < str.memory_size){ - str.str[str.size] = 0; - } - else{ - str.str[str.memory_size-1] = 0; - } - return (char*)str.str; -} - -inline String -substr(String str, int start){ - String result; - result.str = str.str + start; - result.size = str.size - start; - return result; -} - -inline String -substr(String str, int start, int size){ - String result; - result.str = str.str + start; - if (start + size > str.size){ - result.size = str.size - start; - } - else{ - result.size = size; - } - return result; -} - -inline String -substr_slowly(char *str, int start){ - String result; - result.str = str + start; - result.size = str_size(result.str); - return result; -} - -inline String -substr(char *str, int start, int size){ - String result; - result.str = str + start; - result.size = size; - for (int i = 0; i < size; ++i){ - if (result.str[i] == 0){ - result.size = i; - break; - } - } - return result; -} - -inline String -tailstr(String str){ - String result; - result.str = str.str + str.size; - result.memory_size = str.memory_size - str.size; - result.size = 0; - return result; -} - -#endif // #ifndef FCPP_STRING_INC - -#ifdef FCPP_STRING_IMPLEMENTATION - -FCPP_LINK int -str_size(char *str){ - int i = 0; - while (str[i]) ++i; - return i; -} - -FCPP_LINK bool -match(char *a, char *b){ - for (int i = 0;; ++i){ - if (a[i] != b[i]){ - return 0; - } - if (a[i] == 0){ - return 1; - } - } -} - -FCPP_LINK bool -match(String a, char *b){ - int i = 0; - for (; i < a.size; ++i){ - if (a.str[i] != b[i]){ - return 0; - } - } - if (b[i] != 0){ - return 0; - } - return 1; -} - -FCPP_LINK bool -match(String a, String b){ - if (a.size != b.size){ - return 0; - } - for (int i = 0; i < b.size; ++i){ - if (a.str[i] != b.str[i]){ - return 0; - } - } - return 1; -} - -FCPP_LINK bool -match_part(char *a, char *b, int *len){ - int i; - for (i = 0; b[i] != 0; ++i){ - if (a[i] != b[i]){ - return 0; - } - } - *len = i; - return 1; -} - -FCPP_LINK bool -match_part(String a, char *b, int *len){ - int i; - for (i = 0; b[i] != 0; ++i){ - if (a.str[i] != b[i] || i == a.size){ - return 0; - } - } - *len = i; - return 1; -} - -FCPP_LINK bool -match_part(char *a, String b){ - for (int i = 0; i != b.size; ++i){ - if (a[i] != b.str[i]){ - return 0; - } - } - return 1; -} - -FCPP_LINK bool -match_part(String a, String b){ - if (a.size < b.size){ - return 0; - } - for (int i = 0; i < b.size; ++i){ - if (a.str[i] != b.str[i]){ - return 0; - } - } - return 1; -} - -FCPP_LINK bool -match_unsensitive(char *a, char *b){ - for (int i = 0;; ++i){ - if (char_to_upper(a[i]) != - char_to_upper(b[i])){ - return 0; - } - if (a[i] == 0){ - return 1; - } - } -} - -FCPP_LINK bool -match_unsensitive(String a, char *b){ - int i = 0; - for (; i < a.size; ++i){ - if (char_to_upper(a.str[i]) != - char_to_upper(b[i])){ - return 0; - } - } - if (b[i] != 0){ - return 0; - } - return 1; -} - -FCPP_LINK bool -match_unsensitive(String a, String b){ - if (a.size != b.size){ - return 0; - } - for (int i = 0; i < b.size; ++i){ - if (char_to_upper(a.str[i]) != - char_to_upper(b.str[i])){ - return 0; - } - } - return 1; -} - -FCPP_LINK bool -match_part_unsensitive(char *a, char *b, int *len){ - int i; - for (i = 0; b[i] != 0; ++i){ - if (char_to_upper(a[i]) != char_to_upper(b[i])){ - return 0; - } - } - *len = i; - return 1; -} - -FCPP_LINK bool -match_part_unsensitive(String a, char *b, int *len){ - int i; - for (i = 0; b[i] != 0; ++i){ - if (char_to_upper(a.str[i]) != char_to_upper(b[i]) || - i == a.size){ - return 0; - } - } - *len = i; - return 1; -} - -FCPP_LINK bool -match_part_unsensitive(char *a, String b){ - for (int i = 0; i != b.size; ++i){ - if (char_to_upper(a[i]) != char_to_upper(b.str[i])){ - return 0; - } - } - return 1; -} - -FCPP_LINK bool -match_part_unsensitive(String a, String b){ - if (a.size < b.size){ - return 0; - } - for (int i = 0; i < b.size; ++i){ - if (char_to_upper(a.str[i]) != char_to_upper(b.str[i])){ - return 0; - } - } - return 1; -} - -FCPP_LINK int -find(char *str, int start, char character){ - int i = start; - while (str[i] != character && str[i] != 0) ++i; - return i; -} - -FCPP_LINK int -find(String str, int start, char character){ - int i = start; - while (i < str.size && str.str[i] != character) ++i; - return i; -} - -FCPP_LINK int -find(char *str, int start, char *characters){ - int i = start, j; - while (str[i] != 0){ - for (j = 0; characters[j]; ++j){ - if (str[i] == characters[j]){ - return i; - } - } - ++i; - } - return i; -} - -FCPP_LINK int -find(String str, int start, char *characters){ - int i = start, j; - while (i < str.size){ - for (j = 0; characters[j]; ++j){ - if (str.str[i] == characters[j]){ - return i; - } - } - ++i; - } - return i; -} - -FCPP_LINK int -find_substr(char *str, int start, String seek){ - int i, j, k; - bool hit; - - if (seek.size == 0){ - return str_size(str); - } - for (i = start; str[i]; ++i){ - if (str[i] == seek.str[0]){ - hit = 1; - for (j = 1, k = i+1; j < seek.size; ++j, ++k){ - if (str[k] != seek.str[j]){ - hit = 0; - break; - } - } - if (hit){ - return i; - } - } - } - return i; -} - -FCPP_LINK int -find_substr(String str, int start, String seek){ - int stop_at, i, j, k; - bool hit; - - if (seek.size == 0){ - return str.size; - } - stop_at = str.size - seek.size + 1; - for (i = start; i < stop_at; ++i){ - if (str.str[i] == seek.str[0]){ - hit = 1; - for (j = 1, k = i+1; j < seek.size; ++j, ++k){ - if (str.str[k] != seek.str[j]){ - hit = 0; - break; - } - } - if (hit){ - return i; - } - } - } - return str.size; -} - -FCPP_LINK int -rfind_substr(String str, int start, String seek){ - int i, j, k; - bool hit; - - if (seek.size == 0){ - return -1; - } - if (start + seek.size > str.size){ - start = str.size - seek.size; - } - for (i = start; i >= 0; --i){ - if (str.str[i] == seek.str[0]){ - hit = 1; - for (j = 1, k = i+1; j < seek.size; ++j, ++k){ - if (str.str[k] != seek.str[j]){ - hit = 0; - break; - } - } - if (hit){ - return i; - } - } - } - return -1; -} - -FCPP_LINK int -find_substr_unsensitive(char *str, int start, String seek){ - int i, j, k; - bool hit; - char a_upper, b_upper; - - if (seek.size == 0){ - return str_size(str); - } - for (i = start; str[i]; ++i){ - if (str[i] == seek.str[0]){ - hit = 1; - for (j = 1, k = i+1; j < seek.size; ++j, ++k){ - a_upper = char_to_upper(str[k]); - b_upper = char_to_upper(seek.str[j]); - if (a_upper != b_upper){ - hit = 0; - break; - } - } - if (hit){ - return i; - } - } - } - return i; -} - -FCPP_LINK int -find_substr_unsensitive(String str, int start, String seek){ - int i, j, k; - int stop_at; - bool hit; - char a_upper, b_upper; - - if (seek.size == 0){ - return str.size; - } - stop_at = str.size - seek.size + 1; - for (i = start; i < stop_at; ++i){ - if (str.str[i] == seek.str[0]){ - hit = 1; - for (j = 1, k = i+1; j < seek.size; ++j, ++k){ - a_upper = char_to_upper(str.str[k]); - b_upper = char_to_upper(seek.str[j]); - if (a_upper != b_upper){ - hit = 0; - break; - } - } - if (hit){ - return i; - } - } - } - return str.size; -} - -FCPP_LINK int -int_to_str_size(int x){ - int size; - if (x < 0){ - size = 0; - } - else{ - size = 1; - x /= 10; - while (x != 0){ - x /= 10; - ++size; - } - } - return size; -} - -FCPP_LINK int -int_to_str(int x, char *str){ - int size, i, j; - bool negative; - char temp; - - size = 0; - if (x == 0){ - str[0] = '0'; - str[1] = 0; - size = 1; - } - else{ - size = 0; - negative = 0; - if (x < 0){ - negative = 1; - x = -x; - str[size++] = '-'; - } - while (x != 0){ - i = x % 10; - x /= 10; - str[size++] = (char)('0' + i); - } - // NOTE(allen): Start i = 0 if not negative, start i = 1 if is negative - // because - should not be flipped if it is negative :) - for (i = negative, j = size-1; i < j; ++i, --j){ - temp = str[i]; - str[i] = str[j]; - str[j] = temp; - } - str[size] = 0; - } - return size; -} - -FCPP_LINK bool -int_to_str(int x, String *dest){ - bool result = 1; - char *str = dest->str; - int memory_size = dest->memory_size; - int size, i, j; - bool negative; - - if (x == 0){ - str[0] = '0'; - dest->size = 1; - } - else{ - size = 0; - negative = 0; - if (x < 0){ - negative = 1; - x = -x; - str[size++] = '-'; - } - while (x != 0){ - if (size == memory_size){ - result = 0; - break; - } - i = x % 10; - x /= 10; - str[size++] = (char)('0' + i); - } - if (result){ - // NOTE(allen): Start i = 0 if not negative, start i = 1 if is negative - // because - should not be flipped if it is negative :) - for (i = negative, j = size-1; i < j; ++i, --j){ - char temp = str[i]; - str[i] = str[j]; - str[j] = temp; - } - dest->size = size; - } - else{ - dest->size = 0; - } - } - return result; -} - -FCPP_LINK bool -append_int_to_str(int x, String *dest){ - String last_part = tailstr(*dest); - bool result = int_to_str(x, &last_part); - if (result){ - dest->size += last_part.size; - } - return result; -} - -FCPP_LINK int -str_to_int(char *str){ - int x = 0; - for (; *str; ++str){ - if (*str >= '0' || *str <= '9'){ - x *= 10; - x += *str - '0'; - } - else{ - x = 0; - break; - } - } - return(x); -} - -FCPP_LINK int -str_to_int(String str){ - int x, i; - if (str.size == 0){ - x = 0; - } - else{ - x = str.str[0] - '0'; - for (i = 1; i < str.size; ++i){ - x *= 10; - x += str.str[i] - '0'; - } - } - return x; -} - -FCPP_LINK int -hexchar_to_int(char c){ - int x; - if (c >= '0' && c <= '9'){ - x = c-'0'; - } - else if (c > 'F'){ - x = c+(10-'a'); - } - else{ - x = c+(10-'A'); - } - return x; -} - -FCPP_LINK char -int_to_hexchar(int x){ - return (x<10)?((char)x+'0'):((char)x+'a'-10); -} - -FCPP_LINK int -hexstr_to_int(String str){ - int x, i; - if (str.size == 0){ - x = 0; - } - else{ - x = hexchar_to_int(str.str[0]); - for (i = 1; i < str.size; ++i){ - x *= 0x10; - x += hexchar_to_int(str.str[i]); - } - } - return x; -} - -FCPP_LINK int -copy_fast_unsafe(char *dest, char *src){ - char *start = dest; - while (*src != 0){ - *dest = *src; - ++dest; - ++src; - } - return (int)(dest - start); -} - -FCPP_LINK void -copy_fast_unsafe(char *dest, String src){ - int i = 0; - while (i != src.size){ - dest[i] = src.str[i]; - ++i; - } -} - -FCPP_LINK bool -copy_checked(String *dest, String src){ - char *dest_str; - int i; - if (dest->memory_size < src.size){ - return 0; - } - dest_str = dest->str; - for (i = 0; i < src.size; ++i){ - dest_str[i] = src.str[i]; - } - dest->size = src.size; - return 1; -} - -FCPP_LINK bool -copy_partial(String *dest, char *src){ - int i = 0; - int memory_size = dest->memory_size; - char *dest_str = dest->str; - while (src[i] != 0){ - if (i >= memory_size){ - return 0; - } - dest_str[i] = src[i]; - ++i; - } - dest->size = i; - return 1; -} - -FCPP_LINK bool -copy_partial(String *dest, String src){ - bool result; - int memory_size = dest->memory_size; - char *dest_str = dest->str; - if (memory_size < src.size){ - result = 0; - for (int i = 0; i < memory_size; ++i){ - dest_str[i] = src.str[i]; - } - dest->size = memory_size; - } - else{ - result = 1; - for (int i = 0; i < src.size; ++i){ - dest_str[i] = src.str[i]; - } - dest->size = src.size; - } - return result; -} - -FCPP_LINK bool -append_checked(String *dest, String src){ - String end; - end = tailstr(*dest); - bool result = copy_checked(&end, src); - // NOTE(allen): This depends on end.size still being 0 if - // the check failed and no coppy occurred. - dest->size += end.size; - return result; -} - -FCPP_LINK bool -append_partial(String *dest, char *src){ - String end = tailstr(*dest); - bool result = copy_partial(&end, src); - dest->size += end.size; - return result; -} - -FCPP_LINK bool -append_partial(String *dest, String src){ - String end = tailstr(*dest); - bool result = copy_partial(&end, src); - dest->size += end.size; - return result; -} - -FCPP_LINK bool -append(String *dest, char c){ - bool result = 0; - if (dest->size < dest->memory_size){ - dest->str[dest->size++] = c; - result = 1; - } - return result; -} - -FCPP_LINK int -compare(char *a, char *b){ - int i = 0; - while (a[i] == b[i] && a[i] != 0){ - ++i; - } - return (a[i] > b[i]) - (a[i] < b[i]); -} - -FCPP_LINK int -compare(String a, char *b){ - int i = 0; - while (i < a.size && a.str[i] == b[i]){ - ++i; - } - if (i < a.size){ - return (a.str[i] > b[i]) - (a.str[i] < b[i]); - } - else{ - if (b[i] == 0){ - return 0; - } - else{ - return -1; - } - } -} - -FCPP_LINK int -compare(String a, String b){ - int i = 0; - while (i < a.size && i < b.size && a.str[i] == b.str[i]){ - ++i; - } - if (i < a.size && i < b.size){ - return (a.str[i] > b.str[i]) - (a.str[i] < b.str[i]); - } - else{ - return (a.size > b.size) - (a.size < b.size); - } -} - -FCPP_LINK int -reverse_seek_slash(String str, int pos){ - int i = str.size - 1 - pos; - while (i >= 0 && char_not_slash(str.str[i])){ - --i; - } - return i; -} - -FCPP_LINK int -reverse_seek_slash(String str){ - return(reverse_seek_slash(str, 0)); -} - -FCPP_LINK bool -set_last_folder(String *dir, char *folder_name){ - bool result = 0; - int size = reverse_seek_slash(*dir) + 1; - dir->size = size; - if (append(dir, folder_name)){ - if (append(dir, (char*)"\\")){ - result = 1; - } - } - if (!result){ - dir->size = size; - } - return result; -} - -FCPP_LINK bool -set_last_folder(String *dir, String folder_name){ - bool result = 0; - int size = reverse_seek_slash(*dir) + 1; - dir->size = size; - if (append(dir, folder_name)){ - if (append(dir, (char*)"\\")){ - result = 1; - } - } - if (!result){ - dir->size = size; - } - return result; -} - -FCPP_LINK String -file_extension(String str){ - int i; - for (i = str.size - 1; i >= 0; --i){ - if (str.str[i] == '.') break; - } - ++i; - return make_string(str.str+i, str.size-i); -} - -FCPP_LINK String -file_extension_slowly(char *str){ - int s, i; - for (s = 0; str[s]; ++s); - for (i = s - 1; i >= 0; --i){ - if (str[i] == '.') break; - } - ++i; - return make_string(str+i, s-i); -} - -FCPP_LINK bool -remove_last_folder(String *str){ - bool result = 0; - int end = reverse_seek_slash(*str, 1); - if (end >= 0){ - result = 1; - str->size = end + 1; - } - return(result); -} - -// NOTE(allen): experimental section, things below here are -// not promoted to public API level yet. - -#ifndef ArrayCount -#define ArrayCount(a) ((sizeof(a))/sizeof(a)) -#endif - -struct Absolutes{ - String a[8]; - int count; -}; - -FCPP_LINK void -get_absolutes(String name, Absolutes *absolutes, bool implicit_first, bool implicit_last){ - int count = 0; - int max = ArrayCount(absolutes->a) - 1; - if (implicit_last) --max; - - String str; - str.str = name.str; - str.size = 0; - str.memory_size = 0; - bool prev_was_wild = 0; - - if (implicit_first){ - absolutes->a[count++] = str; - prev_was_wild = 1; - } - - int i; - for (i = 0; i < name.size; ++i){ - if (name.str[i] == '*' && count < max){ - if (!prev_was_wild){ - str.memory_size = str.size; - absolutes->a[count++] = str; - str.size = 0; - } - str.str = name.str + i + 1; - prev_was_wild = 1; - } - else{ - ++str.size; - prev_was_wild = 0; - } - } - - str.memory_size = str.size; - absolutes->a[count++] = str; - - if (implicit_last){ - str.size = 0; - str.memory_size = 0; - absolutes->a[count++] = str; - } - - absolutes->count = count; -} - -FCPP_LINK bool -wildcard_match(Absolutes *absolutes, char *x, int case_sensitive){ - bool r = 1; - String *a = absolutes->a; - - bool (*match_func)(char*, String); - bool (*match_part_func)(char*, String); - - if (case_sensitive){ - match_func = match; - match_part_func = match_part; - } - else{ - match_func = match_unsensitive; - match_part_func = match_part_unsensitive; - } - - if (absolutes->count == 1){ - r = match_func(x, *a); - } - else{ - if (!match_part_func(x, *a)){ - r = 0; - } - else{ - String *max = a + absolutes->count - 1; - x += a->size; - ++a; - while (a < max){ - if (*x == 0){ - r = 0; - break; - } - if (match_part_func(x, *a)){ - x += a->size; - ++a; - } - else{ - ++x; - } - } - if (r && a->size > 0){ - r = 0; - while (*x != 0){ - if (match_part_func(x, *a) && *(x + a->size) == 0){ - r = 1; - break; - } - else{ - ++x; - } - } - } - } - } - return r; -} - -FCPP_LINK bool -wildcard_match(Absolutes *absolutes, String x, int case_sensitive){ - terminate_with_null(&x); - return wildcard_match(absolutes, x.str, case_sensitive); -} - -#undef FCPP_STRING_IMPLEMENTATION -#endif // #ifdef FCPP_STRING_IMPLEMENTATION - -// BOTTOM - +/* "4cpp" Open C++ Parser v0.1: String + no warranty implied; use at your own risk + +NOTES ON USE: + OPTIONS: + Set options by defining macros before including this file + + FCPP_STRING_IMPLEMENTATION - causes this file to output function implementations + - this option is unset after use so that future includes of this file + in the same unit do not continue to output implementations + + FCPP_LINK - defines linkage of non-inline functions, defaults to static + FCPP_EXTERN changes FCPP_LINK default to extern, this option is ignored if FCPP_LINK is defined + + include the file "4cpp_clear_config.h" if yo want to undefine all options for some reason + + HIDDEN DEPENDENCIES: + none + */ + +// TOP +// TODO(allen): +// - comments +// - memcpy / memmove replacements (different file for optimization options?) +// + +#include "4coder_config.h" + +#ifndef FCPP_STRING_INC +#define FCPP_STRING_INC + +#ifndef FRED_STRING_STRUCT +#define FRED_STRING_STRUCT +struct String{ + char *str; + int size; + int memory_size; +}; +#endif + +inline bool char_not_slash(char c) { return (c != '\\' && c != '/'); } +inline bool char_is_slash(char c) { return (c == '\\' || c == '/'); } + +inline char char_to_upper(char c) { return (c >= 'a' && c <= 'z') ? c + (char)('A' - 'a') : c; } +inline char char_to_lower(char c) { return (c >= 'A' && c <= 'Z') ? c - (char)('A' - 'a') : c; } + +inline bool char_is_whitespace(char c) { return (c == ' ' || c == '\n' || c == '\r' || c == '\t'); } +inline bool char_is_white_not_r(char c) { return (c == ' ' || c == '\n' || c == '\t'); } +inline bool char_is_lower(char c) { return (c >= 'a' && c <= 'z'); } +inline bool char_is_upper(char c) { return (c >= 'A' && c <= 'Z'); } +inline bool char_is_alpha(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); } +inline bool char_is_alpha_true(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); } +inline bool char_is_numeric(char c) { return (c >= '0' && c <= '9'); } +inline bool char_is_alpha_numeric_true(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'); } +inline bool char_is_alpha_numeric(char c) { return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_'); } +inline bool char_is_hex(char c) { return c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f'; } +inline bool char_is_basic(char c) { return c >= ' ' && c <= '~'; } + +inline String make_string(char *s, int size, int mem_size); +inline String make_string(char *s, int size); + +#define make_lit_string(str) (make_string((char*)(str), sizeof(str)-1, sizeof(str))) +#define make_fixed_width_string(str) (make_string((char*)(str), 0, sizeof(str))) + +#define expand_str(s) ((s).str), ((s).size) + +inline String make_string_slowly(char *s); +inline char* make_c_str(String s); + +inline String substr(String str, int start); +inline String substr(String str, int start, int size); +inline String substr_slowly(char *s, int start); +inline String substr(char *s, int start, int size); +inline String tailstr(String s); + + +FCPP_LINK int str_size(char *s); + +FCPP_LINK bool match(char *a, char *b); +FCPP_LINK bool match(String a, char *b); +inline bool match(char *a, String b) { return match(b,a); } +FCPP_LINK bool match(String a, String b); + +FCPP_LINK bool match_part(char *a, char *b, int *len); +FCPP_LINK bool match_part(String a, char *b, int *len); +inline bool match_part(char *a, char *b) { int x; return match_part(a,b,&x); } +inline bool match_part(String a, char *b) { int x; return match_part(a,b,&x); } +FCPP_LINK bool match_part(char *a, String b); +FCPP_LINK bool match_part(String a, String b); + +FCPP_LINK bool match_unsensitive(char *a, char *b); +FCPP_LINK bool match_unsensitive(String a, char *b); +inline bool match_unsensitive(char *a, String b) { return match_unsensitive(b,a); } +FCPP_LINK bool match_unsensitive(String a, String b); + +FCPP_LINK bool match_part_unsensitive(char *a, char *b, int *len); +FCPP_LINK bool match_part_unsensitive(String a, char *b, int *len); +inline bool match_part_unsensitive(char *a, char *b) { int x; return match_part(a,b,&x); } +inline bool match_part_unsensitive(String a, char *b) { int x; return match_part(a,b,&x); } +FCPP_LINK bool match_part_unsensitive(char *a, String b); +FCPP_LINK bool match_part_unsensitive(String a, String b); + +FCPP_LINK int find(char *s, int start, char c); +FCPP_LINK int find(String s, int start, char c); +FCPP_LINK int find(char *s, int start, char *c); +FCPP_LINK int find(String s, int start, char *c); + +FCPP_LINK int find_substr(char *s, int start, String seek); +FCPP_LINK int find_substr(String s, int start, String seek); +FCPP_LINK int rfind_substr(String s, int start, String seek); + +FCPP_LINK int find_substr_unsensitive(char *s, int start, String seek); +FCPP_LINK int find_substr_unsensitive(String s, int start, String seek); + +inline bool has_substr(char *s, String seek) { return (s[find_substr(s, 0, seek)] != 0); } +inline bool has_substr(String s, String seek) { return (find_substr(s, 0, seek) < s.size); } + +inline bool has_substr_unsensitive(char *s, String seek) { return (s[find_substr_unsensitive(s, 0, seek)] != 0); } +inline bool has_substr_unsensitive(String s, String seek) { return (find_substr_unsensitive(s, 0, seek) < s.size); } + +FCPP_LINK int int_to_str_size(int x); +FCPP_LINK int int_to_str(int x, char *s_out); +FCPP_LINK bool int_to_str(int x, String *s_out); +FCPP_LINK bool append_int_to_str(int x, String *s_out); + +FCPP_LINK int str_to_int(char *s); +FCPP_LINK int str_to_int(String s); +FCPP_LINK int hexchar_to_int(char c); +FCPP_LINK char int_to_hexchar(int c); +FCPP_LINK int hexstr_to_int(String s); + +FCPP_LINK int copy_fast_unsafe(char *dest, char *src); +FCPP_LINK void copy_fast_unsafe(char *dest, String src); +FCPP_LINK bool copy_checked(String *dest, String src); +FCPP_LINK bool copy_partial(String *dest, char *src); +FCPP_LINK bool copy_partial(String *dest, String src); + +inline int copy(char *dest, char *src) { return copy_fast_unsafe(dest, src); } +inline void copy(String *dest, String src) { copy_checked(dest, src); } +inline void copy(String *dest, char *src) { copy_partial(dest, src); } + +FCPP_LINK bool append_checked(String *dest, String src); +FCPP_LINK bool append_partial(String *dest, char *src); +FCPP_LINK bool append_partial(String *dest, String src); + +FCPP_LINK bool append(String *dest, char c); +inline bool append(String *dest, String src) { return append_partial(dest, src); } +inline bool append(String *dest, char *src) { return append_partial(dest, src); } +inline bool terminate_with_null(String *str){ + bool result; + if (str->size < str->memory_size){ + str->str[str->size] = 0; + result = 1; + } + else{ + str->str[str->size-1] = 0; + result = 0; + } + return result; +} + +FCPP_LINK int compare(char *a, char *b); +FCPP_LINK int compare(String a, char *b); +inline int compare(char *a, String b) { return -compare(b,a); } +FCPP_LINK int compare(String a, String b); + +FCPP_LINK int reverse_seek_slash(String str); +FCPP_LINK int reverse_seek_slash(String str, int start_pos); +inline bool get_front_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, reverse_seek_slash(dir) + 1)); } +inline bool get_path_of_directory(String *dest, String dir) { return append_checked(dest, substr(dir, 0, reverse_seek_slash(dir) + 1)); } +FCPP_LINK bool set_last_folder(String *dir, char *folder_name); +FCPP_LINK bool set_last_folder(String *dir, String folder_name); +FCPP_LINK String file_extension(String str); +FCPP_LINK String file_extension_slowly(char *str); +FCPP_LINK bool remove_last_folder(String *str); + +inline String make_string(char *str, int size, int mem_size){ + String result; + result.str = str; + result.size = size; + result.memory_size = mem_size; + return result; +} + +inline String +make_string(char *str, int size){ + String result; + result.str = str; + result.size = size; + result.memory_size = size; + return result; +} + +inline String +make_string_slowly(char *str){ + String result; + result.str = str; + result.size = str_size(str); + result.memory_size = result.size; + return result; +} + +inline char* +make_c_str(String str){ + if (str.size < str.memory_size){ + str.str[str.size] = 0; + } + else{ + str.str[str.memory_size-1] = 0; + } + return (char*)str.str; +} + +inline String +substr(String str, int start){ + String result; + result.str = str.str + start; + result.size = str.size - start; + return result; +} + +inline String +substr(String str, int start, int size){ + String result; + result.str = str.str + start; + if (start + size > str.size){ + result.size = str.size - start; + } + else{ + result.size = size; + } + return result; +} + +inline String +substr_slowly(char *str, int start){ + String result; + result.str = str + start; + result.size = str_size(result.str); + return result; +} + +inline String +substr(char *str, int start, int size){ + String result; + result.str = str + start; + result.size = size; + for (int i = 0; i < size; ++i){ + if (result.str[i] == 0){ + result.size = i; + break; + } + } + return result; +} + +inline String +tailstr(String str){ + String result; + result.str = str.str + str.size; + result.memory_size = str.memory_size - str.size; + result.size = 0; + return result; +} + +#endif // #ifndef FCPP_STRING_INC + +#ifdef FCPP_STRING_IMPLEMENTATION + +FCPP_LINK int +str_size(char *str){ + int i = 0; + while (str[i]) ++i; + return i; +} + +FCPP_LINK bool +match(char *a, char *b){ + for (int i = 0;; ++i){ + if (a[i] != b[i]){ + return 0; + } + if (a[i] == 0){ + return 1; + } + } +} + +FCPP_LINK bool +match(String a, char *b){ + int i = 0; + for (; i < a.size; ++i){ + if (a.str[i] != b[i]){ + return 0; + } + } + if (b[i] != 0){ + return 0; + } + return 1; +} + +FCPP_LINK bool +match(String a, String b){ + if (a.size != b.size){ + return 0; + } + for (int i = 0; i < b.size; ++i){ + if (a.str[i] != b.str[i]){ + return 0; + } + } + return 1; +} + +FCPP_LINK bool +match_part(char *a, char *b, int *len){ + int i; + for (i = 0; b[i] != 0; ++i){ + if (a[i] != b[i]){ + return 0; + } + } + *len = i; + return 1; +} + +FCPP_LINK bool +match_part(String a, char *b, int *len){ + int i; + for (i = 0; b[i] != 0; ++i){ + if (a.str[i] != b[i] || i == a.size){ + return 0; + } + } + *len = i; + return 1; +} + +FCPP_LINK bool +match_part(char *a, String b){ + for (int i = 0; i != b.size; ++i){ + if (a[i] != b.str[i]){ + return 0; + } + } + return 1; +} + +FCPP_LINK bool +match_part(String a, String b){ + if (a.size < b.size){ + return 0; + } + for (int i = 0; i < b.size; ++i){ + if (a.str[i] != b.str[i]){ + return 0; + } + } + return 1; +} + +FCPP_LINK bool +match_unsensitive(char *a, char *b){ + for (int i = 0;; ++i){ + if (char_to_upper(a[i]) != + char_to_upper(b[i])){ + return 0; + } + if (a[i] == 0){ + return 1; + } + } +} + +FCPP_LINK bool +match_unsensitive(String a, char *b){ + int i = 0; + for (; i < a.size; ++i){ + if (char_to_upper(a.str[i]) != + char_to_upper(b[i])){ + return 0; + } + } + if (b[i] != 0){ + return 0; + } + return 1; +} + +FCPP_LINK bool +match_unsensitive(String a, String b){ + if (a.size != b.size){ + return 0; + } + for (int i = 0; i < b.size; ++i){ + if (char_to_upper(a.str[i]) != + char_to_upper(b.str[i])){ + return 0; + } + } + return 1; +} + +FCPP_LINK bool +match_part_unsensitive(char *a, char *b, int *len){ + int i; + for (i = 0; b[i] != 0; ++i){ + if (char_to_upper(a[i]) != char_to_upper(b[i])){ + return 0; + } + } + *len = i; + return 1; +} + +FCPP_LINK bool +match_part_unsensitive(String a, char *b, int *len){ + int i; + for (i = 0; b[i] != 0; ++i){ + if (char_to_upper(a.str[i]) != char_to_upper(b[i]) || + i == a.size){ + return 0; + } + } + *len = i; + return 1; +} + +FCPP_LINK bool +match_part_unsensitive(char *a, String b){ + for (int i = 0; i != b.size; ++i){ + if (char_to_upper(a[i]) != char_to_upper(b.str[i])){ + return 0; + } + } + return 1; +} + +FCPP_LINK bool +match_part_unsensitive(String a, String b){ + if (a.size < b.size){ + return 0; + } + for (int i = 0; i < b.size; ++i){ + if (char_to_upper(a.str[i]) != char_to_upper(b.str[i])){ + return 0; + } + } + return 1; +} + +FCPP_LINK int +find(char *str, int start, char character){ + int i = start; + while (str[i] != character && str[i] != 0) ++i; + return i; +} + +FCPP_LINK int +find(String str, int start, char character){ + int i = start; + while (i < str.size && str.str[i] != character) ++i; + return i; +} + +FCPP_LINK int +find(char *str, int start, char *characters){ + int i = start, j; + while (str[i] != 0){ + for (j = 0; characters[j]; ++j){ + if (str[i] == characters[j]){ + return i; + } + } + ++i; + } + return i; +} + +FCPP_LINK int +find(String str, int start, char *characters){ + int i = start, j; + while (i < str.size){ + for (j = 0; characters[j]; ++j){ + if (str.str[i] == characters[j]){ + return i; + } + } + ++i; + } + return i; +} + +FCPP_LINK int +find_substr(char *str, int start, String seek){ + int i, j, k; + bool hit; + + if (seek.size == 0){ + return str_size(str); + } + for (i = start; str[i]; ++i){ + if (str[i] == seek.str[0]){ + hit = 1; + for (j = 1, k = i+1; j < seek.size; ++j, ++k){ + if (str[k] != seek.str[j]){ + hit = 0; + break; + } + } + if (hit){ + return i; + } + } + } + return i; +} + +FCPP_LINK int +find_substr(String str, int start, String seek){ + int stop_at, i, j, k; + bool hit; + + if (seek.size == 0){ + return str.size; + } + stop_at = str.size - seek.size + 1; + for (i = start; i < stop_at; ++i){ + if (str.str[i] == seek.str[0]){ + hit = 1; + for (j = 1, k = i+1; j < seek.size; ++j, ++k){ + if (str.str[k] != seek.str[j]){ + hit = 0; + break; + } + } + if (hit){ + return i; + } + } + } + return str.size; +} + +FCPP_LINK int +rfind_substr(String str, int start, String seek){ + int i, j, k; + bool hit; + + if (seek.size == 0){ + return -1; + } + if (start + seek.size > str.size){ + start = str.size - seek.size; + } + for (i = start; i >= 0; --i){ + if (str.str[i] == seek.str[0]){ + hit = 1; + for (j = 1, k = i+1; j < seek.size; ++j, ++k){ + if (str.str[k] != seek.str[j]){ + hit = 0; + break; + } + } + if (hit){ + return i; + } + } + } + return -1; +} + +FCPP_LINK int +find_substr_unsensitive(char *str, int start, String seek){ + int i, j, k; + bool hit; + char a_upper, b_upper; + + if (seek.size == 0){ + return str_size(str); + } + for (i = start; str[i]; ++i){ + if (str[i] == seek.str[0]){ + hit = 1; + for (j = 1, k = i+1; j < seek.size; ++j, ++k){ + a_upper = char_to_upper(str[k]); + b_upper = char_to_upper(seek.str[j]); + if (a_upper != b_upper){ + hit = 0; + break; + } + } + if (hit){ + return i; + } + } + } + return i; +} + +FCPP_LINK int +find_substr_unsensitive(String str, int start, String seek){ + int i, j, k; + int stop_at; + bool hit; + char a_upper, b_upper; + + if (seek.size == 0){ + return str.size; + } + stop_at = str.size - seek.size + 1; + for (i = start; i < stop_at; ++i){ + if (str.str[i] == seek.str[0]){ + hit = 1; + for (j = 1, k = i+1; j < seek.size; ++j, ++k){ + a_upper = char_to_upper(str.str[k]); + b_upper = char_to_upper(seek.str[j]); + if (a_upper != b_upper){ + hit = 0; + break; + } + } + if (hit){ + return i; + } + } + } + return str.size; +} + +FCPP_LINK int +int_to_str_size(int x){ + int size; + if (x < 0){ + size = 0; + } + else{ + size = 1; + x /= 10; + while (x != 0){ + x /= 10; + ++size; + } + } + return size; +} + +FCPP_LINK int +int_to_str(int x, char *str){ + int size, i, j; + bool negative; + char temp; + + size = 0; + if (x == 0){ + str[0] = '0'; + str[1] = 0; + size = 1; + } + else{ + size = 0; + negative = 0; + if (x < 0){ + negative = 1; + x = -x; + str[size++] = '-'; + } + while (x != 0){ + i = x % 10; + x /= 10; + str[size++] = (char)('0' + i); + } + // NOTE(allen): Start i = 0 if not negative, start i = 1 if is negative + // because - should not be flipped if it is negative :) + for (i = negative, j = size-1; i < j; ++i, --j){ + temp = str[i]; + str[i] = str[j]; + str[j] = temp; + } + str[size] = 0; + } + return size; +} + +FCPP_LINK bool +int_to_str(int x, String *dest){ + bool result = 1; + char *str = dest->str; + int memory_size = dest->memory_size; + int size, i, j; + bool negative; + + if (x == 0){ + str[0] = '0'; + dest->size = 1; + } + else{ + size = 0; + negative = 0; + if (x < 0){ + negative = 1; + x = -x; + str[size++] = '-'; + } + while (x != 0){ + if (size == memory_size){ + result = 0; + break; + } + i = x % 10; + x /= 10; + str[size++] = (char)('0' + i); + } + if (result){ + // NOTE(allen): Start i = 0 if not negative, start i = 1 if is negative + // because - should not be flipped if it is negative :) + for (i = negative, j = size-1; i < j; ++i, --j){ + char temp = str[i]; + str[i] = str[j]; + str[j] = temp; + } + dest->size = size; + } + else{ + dest->size = 0; + } + } + return result; +} + +FCPP_LINK bool +append_int_to_str(int x, String *dest){ + String last_part = tailstr(*dest); + bool result = int_to_str(x, &last_part); + if (result){ + dest->size += last_part.size; + } + return result; +} + +FCPP_LINK int +str_to_int(char *str){ + int x = 0; + for (; *str; ++str){ + if (*str >= '0' || *str <= '9'){ + x *= 10; + x += *str - '0'; + } + else{ + x = 0; + break; + } + } + return(x); +} + +FCPP_LINK int +str_to_int(String str){ + int x, i; + if (str.size == 0){ + x = 0; + } + else{ + x = str.str[0] - '0'; + for (i = 1; i < str.size; ++i){ + x *= 10; + x += str.str[i] - '0'; + } + } + return x; +} + +FCPP_LINK int +hexchar_to_int(char c){ + int x; + if (c >= '0' && c <= '9'){ + x = c-'0'; + } + else if (c > 'F'){ + x = c+(10-'a'); + } + else{ + x = c+(10-'A'); + } + return x; +} + +FCPP_LINK char +int_to_hexchar(int x){ + return (x<10)?((char)x+'0'):((char)x+'a'-10); +} + +FCPP_LINK int +hexstr_to_int(String str){ + int x, i; + if (str.size == 0){ + x = 0; + } + else{ + x = hexchar_to_int(str.str[0]); + for (i = 1; i < str.size; ++i){ + x *= 0x10; + x += hexchar_to_int(str.str[i]); + } + } + return x; +} + +FCPP_LINK int +copy_fast_unsafe(char *dest, char *src){ + char *start = dest; + while (*src != 0){ + *dest = *src; + ++dest; + ++src; + } + return (int)(dest - start); +} + +FCPP_LINK void +copy_fast_unsafe(char *dest, String src){ + int i = 0; + while (i != src.size){ + dest[i] = src.str[i]; + ++i; + } +} + +FCPP_LINK bool +copy_checked(String *dest, String src){ + char *dest_str; + int i; + if (dest->memory_size < src.size){ + return 0; + } + dest_str = dest->str; + for (i = 0; i < src.size; ++i){ + dest_str[i] = src.str[i]; + } + dest->size = src.size; + return 1; +} + +FCPP_LINK bool +copy_partial(String *dest, char *src){ + int i = 0; + int memory_size = dest->memory_size; + char *dest_str = dest->str; + while (src[i] != 0){ + if (i >= memory_size){ + return 0; + } + dest_str[i] = src[i]; + ++i; + } + dest->size = i; + return 1; +} + +FCPP_LINK bool +copy_partial(String *dest, String src){ + bool result; + int memory_size = dest->memory_size; + char *dest_str = dest->str; + if (memory_size < src.size){ + result = 0; + for (int i = 0; i < memory_size; ++i){ + dest_str[i] = src.str[i]; + } + dest->size = memory_size; + } + else{ + result = 1; + for (int i = 0; i < src.size; ++i){ + dest_str[i] = src.str[i]; + } + dest->size = src.size; + } + return result; +} + +FCPP_LINK bool +append_checked(String *dest, String src){ + String end; + end = tailstr(*dest); + bool result = copy_checked(&end, src); + // NOTE(allen): This depends on end.size still being 0 if + // the check failed and no coppy occurred. + dest->size += end.size; + return result; +} + +FCPP_LINK bool +append_partial(String *dest, char *src){ + String end = tailstr(*dest); + bool result = copy_partial(&end, src); + dest->size += end.size; + return result; +} + +FCPP_LINK bool +append_partial(String *dest, String src){ + String end = tailstr(*dest); + bool result = copy_partial(&end, src); + dest->size += end.size; + return result; +} + +FCPP_LINK bool +append(String *dest, char c){ + bool result = 0; + if (dest->size < dest->memory_size){ + dest->str[dest->size++] = c; + result = 1; + } + return result; +} + +FCPP_LINK int +compare(char *a, char *b){ + int i = 0; + while (a[i] == b[i] && a[i] != 0){ + ++i; + } + return (a[i] > b[i]) - (a[i] < b[i]); +} + +FCPP_LINK int +compare(String a, char *b){ + int i = 0; + while (i < a.size && a.str[i] == b[i]){ + ++i; + } + if (i < a.size){ + return (a.str[i] > b[i]) - (a.str[i] < b[i]); + } + else{ + if (b[i] == 0){ + return 0; + } + else{ + return -1; + } + } +} + +FCPP_LINK int +compare(String a, String b){ + int i = 0; + while (i < a.size && i < b.size && a.str[i] == b.str[i]){ + ++i; + } + if (i < a.size && i < b.size){ + return (a.str[i] > b.str[i]) - (a.str[i] < b.str[i]); + } + else{ + return (a.size > b.size) - (a.size < b.size); + } +} + +FCPP_LINK int +reverse_seek_slash(String str, int pos){ + int i = str.size - 1 - pos; + while (i >= 0 && char_not_slash(str.str[i])){ + --i; + } + return i; +} + +FCPP_LINK int +reverse_seek_slash(String str){ + return(reverse_seek_slash(str, 0)); +} + +FCPP_LINK bool +set_last_folder(String *dir, char *folder_name){ + bool result = 0; + int size = reverse_seek_slash(*dir) + 1; + dir->size = size; + if (append(dir, folder_name)){ + if (append(dir, (char*)"\\")){ + result = 1; + } + } + if (!result){ + dir->size = size; + } + return result; +} + +FCPP_LINK bool +set_last_folder(String *dir, String folder_name){ + bool result = 0; + int size = reverse_seek_slash(*dir) + 1; + dir->size = size; + if (append(dir, folder_name)){ + if (append(dir, (char*)"\\")){ + result = 1; + } + } + if (!result){ + dir->size = size; + } + return result; +} + +FCPP_LINK String +file_extension(String str){ + int i; + for (i = str.size - 1; i >= 0; --i){ + if (str.str[i] == '.') break; + } + ++i; + return make_string(str.str+i, str.size-i); +} + +FCPP_LINK String +file_extension_slowly(char *str){ + int s, i; + for (s = 0; str[s]; ++s); + for (i = s - 1; i >= 0; --i){ + if (str[i] == '.') break; + } + ++i; + return make_string(str+i, s-i); +} + +FCPP_LINK bool +remove_last_folder(String *str){ + bool result = 0; + int end = reverse_seek_slash(*str, 1); + if (end >= 0){ + result = 1; + str->size = end + 1; + } + return(result); +} + +// NOTE(allen): experimental section, things below here are +// not promoted to public API level yet. + +#ifndef ArrayCount +#define ArrayCount(a) ((sizeof(a))/sizeof(a)) +#endif + +struct Absolutes{ + String a[8]; + int count; +}; + +FCPP_LINK void +get_absolutes(String name, Absolutes *absolutes, bool implicit_first, bool implicit_last){ + int count = 0; + int max = ArrayCount(absolutes->a) - 1; + if (implicit_last) --max; + + String str; + str.str = name.str; + str.size = 0; + str.memory_size = 0; + bool prev_was_wild = 0; + + if (implicit_first){ + absolutes->a[count++] = str; + prev_was_wild = 1; + } + + int i; + for (i = 0; i < name.size; ++i){ + if (name.str[i] == '*' && count < max){ + if (!prev_was_wild){ + str.memory_size = str.size; + absolutes->a[count++] = str; + str.size = 0; + } + str.str = name.str + i + 1; + prev_was_wild = 1; + } + else{ + ++str.size; + prev_was_wild = 0; + } + } + + str.memory_size = str.size; + absolutes->a[count++] = str; + + if (implicit_last){ + str.size = 0; + str.memory_size = 0; + absolutes->a[count++] = str; + } + + absolutes->count = count; +} + +FCPP_LINK bool +wildcard_match(Absolutes *absolutes, char *x, int case_sensitive){ + bool r = 1; + String *a = absolutes->a; + + bool (*match_func)(char*, String); + bool (*match_part_func)(char*, String); + + if (case_sensitive){ + match_func = match; + match_part_func = match_part; + } + else{ + match_func = match_unsensitive; + match_part_func = match_part_unsensitive; + } + + if (absolutes->count == 1){ + r = match_func(x, *a); + } + else{ + if (!match_part_func(x, *a)){ + r = 0; + } + else{ + String *max = a + absolutes->count - 1; + x += a->size; + ++a; + while (a < max){ + if (*x == 0){ + r = 0; + break; + } + if (match_part_func(x, *a)){ + x += a->size; + ++a; + } + else{ + ++x; + } + } + if (r && a->size > 0){ + r = 0; + while (*x != 0){ + if (match_part_func(x, *a) && *(x + a->size) == 0){ + r = 1; + break; + } + else{ + ++x; + } + } + } + } + } + return r; +} + +FCPP_LINK bool +wildcard_match(Absolutes *absolutes, String x, int case_sensitive){ + terminate_with_null(&x); + return wildcard_match(absolutes, x.str, case_sensitive); +} + +#undef FCPP_STRING_IMPLEMENTATION +#endif // #ifdef FCPP_STRING_IMPLEMENTATION + +// BOTTOM + diff --git a/4cpp_lexer.h b/4cpp_lexer.h index 0fa00cb8..1e5e80c7 100644 --- a/4cpp_lexer.h +++ b/4cpp_lexer.h @@ -220,6 +220,7 @@ enum Cpp_Token_Type{ CPP_PP_UNKNOWN, CPP_TOKEN_DEFINED, CPP_TOKEN_INCLUDE_FILE, + CPP_TOKEN_ERROR_MESSAGE, // NOTE(allen): used in the parser CPP_TOKEN_EOF @@ -256,6 +257,7 @@ enum Cpp_Preprocessor_State{ CPP_LEX_PP_BODY, CPP_LEX_PP_BODY_IF, CPP_LEX_PP_NUMBER, + CPP_LEX_PP_ERROR, CPP_LEX_PP_JUNK, // NEVER ADD BELOW THIS CPP_LEX_PP_COUNT @@ -450,6 +452,7 @@ FCPP_GLOBAL String_And_Flag keyword_strings[] = { {"long", CPP_TOKEN_KEY_MODIFIER}, {"short", CPP_TOKEN_KEY_MODIFIER}, + {"unsigned", CPP_TOKEN_KEY_MODIFIER}, {"const", CPP_TOKEN_KEY_QUALIFIER}, {"volatile", CPP_TOKEN_KEY_QUALIFIER}, @@ -766,7 +769,7 @@ cpp_read_junk_line(Cpp_File file, int pos){ --pos; } result.pos = pos; - result.token.size = pos - result.token.start - 1; + result.token.size = pos - result.token.start; } return result; @@ -1348,6 +1351,9 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ lex.pp_state = CPP_LEX_PP_NUMBER; break; case CPP_PP_ERROR: + lex.pp_state = CPP_LEX_PP_ERROR; + break; + case CPP_PP_UNKNOWN: case CPP_PP_ELSE: case CPP_PP_ENDIF: @@ -1383,7 +1389,8 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ } else{ - if (lex.pp_state == CPP_LEX_PP_IDENTIFIER){ + switch (lex.pp_state){ + case CPP_LEX_PP_IDENTIFIER: if (!char_is_alpha_numeric(current)){ has_result = 0; lex.pp_state = CPP_LEX_PP_JUNK; @@ -1394,8 +1401,9 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ lex.pos = result.pos; lex.pp_state = CPP_LEX_PP_JUNK; } - } - else if (lex.pp_state == CPP_LEX_PP_MACRO_IDENTIFIER){ + break; + + case CPP_LEX_PP_MACRO_IDENTIFIER: if (!char_is_alpha_numeric(current)){ has_result = 0; lex.pp_state = CPP_LEX_PP_JUNK; @@ -1406,9 +1414,9 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ lex.pos = result.pos; lex.pp_state = CPP_LEX_PP_BODY; } - } - - else if (lex.pp_state == CPP_LEX_PP_INCLUDE){ + break; + + case CPP_LEX_PP_INCLUDE: if (current != '"' && current != '<'){ has_result = 0; lex.pp_state = CPP_LEX_PP_JUNK; @@ -1418,8 +1426,9 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ lex.pos = result.pos; lex.pp_state = CPP_LEX_PP_JUNK; } - } - else if (lex.pp_state == CPP_LEX_PP_BODY){ + break; + + case CPP_LEX_PP_BODY: if (current == '#'){ result = cpp_read_pp_operator(file, lex.pos); } @@ -1428,8 +1437,9 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ } lex.pos = result.pos; result.token.flags |= CPP_TFLAG_PP_BODY; - } - else if (lex.pp_state == CPP_LEX_PP_BODY_IF){ + break; + + case CPP_LEX_PP_BODY_IF: if (current == '#'){ result = cpp_read_pp_operator(file, lex.pos); } @@ -1438,9 +1448,9 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ } lex.pos = result.pos; result.token.flags |= CPP_TFLAG_PP_BODY; - } - - else if (lex.pp_state == CPP_LEX_PP_NUMBER){ + break; + + case CPP_LEX_PP_NUMBER: if (!char_is_numeric(current)){ has_result = 0; lex.pp_state = CPP_LEX_PP_JUNK; @@ -1451,8 +1461,17 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ result.token.flags |= CPP_TFLAG_PP_BODY; lex.pp_state = CPP_LEX_PP_INCLUDE; } - } - else{ + break; + + case CPP_LEX_PP_ERROR: + result = cpp_read_junk_line(file, lex.pos); + lex.pos = result.pos; + result.token.type = CPP_TOKEN_ERROR_MESSAGE; + result.token.flags |= CPP_TFLAG_PP_BODY; + break; + + default: + { bool took_comment = 0; if (current == '/' && lex.pos + 1 < file.size){ if (file.data[lex.pos + 1] == '/'){ @@ -1472,6 +1491,8 @@ cpp_lex_step(Cpp_File file, Cpp_Lex_Data *lex_data){ lex.pos = result.pos; result.token.flags |= CPP_TFLAG_PP_BODY; } + }break; + } } } diff --git a/4ed.cpp b/4ed.cpp index faedbccd..00000dea 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -122,7 +122,7 @@ app_get_map_index(App_Vars *vars, i32 mapid){ internal Command_Map* app_get_map(App_Vars *vars, i32 mapid){ Command_Map *map = 0; - if (mapid >= mapid_user_custom) map = vars->user_maps + mapid - mapid_user_custom; + if (mapid < mapid_global) map = vars->user_maps + mapid; else if (mapid == mapid_global) map = &vars->map_top; else if (mapid == mapid_file) map = &vars->map_file; return map; @@ -1065,10 +1065,12 @@ COMMAND_DECL(kill_buffer){ COMMAND_DECL(toggle_line_wrap){ ProfileMomentFunction(); REQ_FILE_VIEW(view); + REQ_FILE(file, view); Relative_Scrolling scrolling = view_get_relative_scrolling(view); if (view->unwrapped_lines){ view->unwrapped_lines = 0; + file->settings.unwrapped_lines = 0; view->target_x = 0; view->cursor = view_compute_cursor_from_pos(view, view->cursor.pos); @@ -1076,6 +1078,7 @@ COMMAND_DECL(toggle_line_wrap){ } else{ view->unwrapped_lines = 1; + file->settings.unwrapped_lines = 1; view->cursor = view_compute_cursor_from_pos(view, view->cursor.pos); view->preferred_x = view->cursor.unwrapped_x; @@ -1660,6 +1663,8 @@ COMMAND_DECL(set_settings){ if (view->unwrapped_lines){ if (v){ view->unwrapped_lines = 0; + file->settings.unwrapped_lines = 0; + if (!file->state.is_loading){ Relative_Scrolling scrolling = view_get_relative_scrolling(view); view->target_x = 0; @@ -1672,6 +1677,7 @@ COMMAND_DECL(set_settings){ else{ if (!v){ view->unwrapped_lines = 1; + file->settings.unwrapped_lines = 1; if (!file->state.is_loading){ Relative_Scrolling scrolling = view_get_relative_scrolling(view); @@ -1688,7 +1694,7 @@ COMMAND_DECL(set_settings){ int v = dynamic_to_int(¶m->param.value); if (v == mapid_global) file->settings.base_map_id = mapid_global; else if (v == mapid_file) file->settings.base_map_id = mapid_file; - else if (v >= mapid_user_custom){ + else if (v < mapid_global){ int index = app_get_map_index(vars, v); if (index < vars->user_map_count) file->settings.base_map_id = v; else file->settings.base_map_id = mapid_file; @@ -2047,16 +2053,23 @@ setup_debug_commands(Command_Map *commands, Partition *part, Key_Codes *codes, C internal void setup_ui_commands(Command_Map *commands, Partition *part, Key_Codes *codes, Command_Map *parent){ - map_init(commands, part, 12, parent); + map_init(commands, part, 32, parent); commands->vanilla_keyboard_default.function = command_null; - map_add(commands, codes->left, MDFR_NONE, command_null); - map_add(commands, codes->right, MDFR_NONE, command_null); - map_add(commands, codes->up, MDFR_NONE, command_null); - map_add(commands, codes->down, MDFR_NONE, command_null); - map_add(commands, codes->back, MDFR_NONE, command_null); - map_add(commands, codes->esc, MDFR_NONE, command_close_minor_view); + // TODO(allen): This is hacky, when the new UI stuff happens, let's fix it, and by that + // I mean actually fix it, don't just say you fixed it with something stupid again. + u8 mdfr; + u8 mdfr_array[] = {MDFR_NONE, MDFR_SHIFT, MDFR_CTRL, MDFR_SHIFT | MDFR_CTRL}; + for (i32 i = 0; i < 4; ++i){ + mdfr = mdfr_array[i]; + map_add(commands, codes->left, mdfr, command_null); + map_add(commands, codes->right, mdfr, command_null); + map_add(commands, codes->up, mdfr, command_null); + map_add(commands, codes->down, mdfr, command_null); + map_add(commands, codes->back, mdfr, command_null); + map_add(commands, codes->esc, mdfr, command_close_minor_view); + } } internal void @@ -2492,86 +2505,134 @@ HOOK_SIG(default_open_file_hook){ } enum Command_Line_Action{ + CLAct_Nothing, CLAct_Ignore, CLAct_UserFile, CLAct_CustomDLL, CLAct_InitialFilePosition, CLAct_WindowSize, + CLAct_WindowMaximize, CLAct_WindowPosition, CLAct_Count }; void -init_command_line_settings(App_Settings *settings, App_Plat_Settings *plat_settings, +init_command_line_settings(App_Settings *settings, Plat_Settings *plat_settings, Command_Line_Parameters clparams){ char *arg; - Command_Line_Action action; + Command_Line_Action action = CLAct_Nothing; i32 i,index; b32 strict = 0; settings->init_files_max = ArrayCount(settings->init_files); - for (i = 1; i < clparams.argc; ++i){ - arg = clparams.argv[i]; - if (arg[0] == '-'){ - action = CLAct_Ignore; - switch (arg[1]){ - case 'u': action = CLAct_UserFile; strict = 0; break; - case 'U': action = CLAct_UserFile; strict = 1; break; - - case 'd': action = CLAct_CustomDLL; strict = 0; break; - case 'D': action = CLAct_CustomDLL; strict = 1; break; - - case 'l': action = CLAct_InitialFilePosition; break; - - case 'w': action = CLAct_WindowSize; break; - case 'p': action = CLAct_WindowPosition; break; - } - - switch (action){ + for (i = 1; i <= clparams.argc; ++i){ + if (i == clparams.argc) arg = ""; + else arg = clparams.argv[i]; + switch (action){ + case CLAct_Nothing: + { + if (arg[0] == '-'){ + action = CLAct_Ignore; + switch (arg[1]){ + case 'u': action = CLAct_UserFile; strict = 0; break; + case 'U': action = CLAct_UserFile; strict = 1; break; + + case 'd': action = CLAct_CustomDLL; strict = 0; break; + case 'D': action = CLAct_CustomDLL; strict = 1; break; + + case 'l': action = CLAct_InitialFilePosition; break; + + case 'w': action = CLAct_WindowSize; break; + case 'W': action = CLAct_WindowMaximize; break; + case 'p': action = CLAct_WindowPosition; break; + } + } + else if (arg[0] != 0){ + if (settings->init_files_count < settings->init_files_max){ + index = settings->init_files_count++; + settings->init_files[index] = arg; + } + } + }break; + case CLAct_UserFile: + { settings->user_file_is_strict = strict; - ++i; if (i < clparams.argc){ settings->user_file = clparams.argv[i]; } - break; - + action = CLAct_Nothing; + }break; + case CLAct_CustomDLL: + { plat_settings->custom_dll_is_strict = strict; - ++i; if (i < clparams.argc){ plat_settings->custom_dll = clparams.argv[i]; } - break; + action = CLAct_Nothing; + }break; case CLAct_InitialFilePosition: - ++i; + { if (i < clparams.argc){ settings->initial_line = str_to_int(clparams.argv[i]); } - break; + action = CLAct_Nothing; + }break; case CLAct_WindowSize: - break; - - case CLAct_WindowPosition: - break; - } + { + if (i + 1 < clparams.argc){ + plat_settings->set_window_size = 1; + plat_settings->window_w = str_to_int(clparams.argv[i]); + plat_settings->window_h = str_to_int(clparams.argv[i+1]); + + ++i; + } + action = CLAct_Nothing; + }break; + + case CLAct_WindowMaximize: + { + --i; + plat_settings->maximize_window = 1; + action = CLAct_Nothing; + }break; - } - else{ - if (settings->init_files_count < settings->init_files_max){ - index = settings->init_files_count++; - settings->init_files[index] = arg; - } + case CLAct_WindowPosition: + { + if (i + 1 < clparams.argc){ + plat_settings->set_window_pos = 1; + plat_settings->window_x = str_to_int(clparams.argv[i]); + plat_settings->window_y = str_to_int(clparams.argv[i+1]); + + ++i; + } + action = CLAct_Nothing; + }break; } } } +internal App_Vars* +app_setup_memory(Application_Memory *memory){ + Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); + App_Vars *vars = push_struct(&_partition, App_Vars); + Assert(vars); + *vars = {}; + vars->mem.part = _partition; + + general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); + + return(vars); +} + App_Read_Command_Line_Sig(app_read_command_line){ i32 output_size = 0; - //init_command_line_settings(); + App_Vars *vars = app_setup_memory(memory); + init_command_line_settings(&vars->settings, plat_settings, clparams); return(output_size); } @@ -2579,17 +2640,11 @@ App_Read_Command_Line_Sig(app_read_command_line){ App_Init_Sig(app_init){ app_links_init(system); - Partition _partition = partition_open(memory->vars_memory, memory->vars_memory_size); - App_Vars *vars = push_struct(&_partition, App_Vars); - Assert(vars); - *vars = {}; + App_Vars *vars = (App_Vars*)memory->vars_memory; vars->config_api = api; - vars->mem.part = _partition; Partition *partition = &vars->mem.part; target->partition = partition; - general_memory_open(&vars->mem.general, memory->target_memory, memory->target_memory_size); - i32 panel_max_count = vars->layout.panel_max_count = 16; i32 divider_max_count = panel_max_count - 1; vars->layout.panel_count = 1; @@ -2687,7 +2742,7 @@ App_Init_Sig(app_init){ map_init(mapptr, &vars->mem.part, table_max, global); did_file = 1; } - else if (mapid >= mapid_user_custom){ + else if (mapid < mapid_global){ i32 index = app_get_or_add_map_index(vars, mapid); Assert(index < user_map_count); mapptr = vars->user_maps + index; @@ -2702,7 +2757,7 @@ App_Init_Sig(app_init){ int mapid = unit->map_inherit.mapid; if (mapid == mapid_global) parent = &vars->map_top; else if (mapid == mapid_file) parent = &vars->map_file; - else if (mapid >= mapid_user_custom){ + else if (mapid < mapid_global){ i32 index = app_get_or_add_map_index(vars, mapid); if (index < user_map_count) parent = vars->user_maps + index; else parent = 0; @@ -2819,27 +2874,6 @@ App_Init_Sig(app_init){ font_set_add(partition, vars->font_set, file_name, name, pt_size); } - -#if 0 - if (vars->config_api.set_extra_font){ - Extra_Font extra; - extra.size = 17; - vars->config_api.set_extra_font(&extra); - memory_used = 0; - if (app_load_font(target, - vars->fonts.fonts + font_count, extra.file_name, extra.size, - partition_current(partition), - &memory_used, 4, make_string_slowly(extra.font_name))){ - ++font_count; - } - else{ - vars->fonts.fonts[font_count] = {}; - } - push_block(partition, memory_used); - } - - vars->fonts.count = font_count; -#endif } // NOTE(allen): file setup @@ -2918,6 +2952,7 @@ App_Step_Sig(app_step){ copy(dest, make_string((char*)clipboard.str, clipboard.size)); } + // TODO(allen): profile this make sure it's not costing me too much power. // NOTE(allen): check files are up to date for (i32 i = 0; i < vars->working_set.file_index_count; ++i){ Editing_File *file = vars->working_set.files + i; @@ -3277,9 +3312,19 @@ App_Step_Sig(app_step){ Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part); command_data.part = partition_sub_part(&vars->mem.part, 16 << 10); - if (first_step && vars->hooks[hook_start]){ - vars->hooks[hook_start](&command_data, &app_links); - command_data.part.pos = 0; + if (first_step){ + if (vars->hooks[hook_start]){ + vars->hooks[hook_start](&command_data, &app_links); + command_data.part.pos = 0; + } + + char *file_name; + i32 i; + for (i = 0; i < vars->settings.init_file_count; ++i){ + file_name = vars->settings.init_files[i]; + // TODO(allen): open files, do not attach to view + //app_open_file(system, vars, exchange,live_set, working_set, panel,command, string.str, string.size); + } } // NOTE(allen): command input to active view @@ -3366,7 +3411,7 @@ App_Step_Sig(app_step){ Assert(view_->do_view); b32 active = (panel == active_panel); Input_Summary input = (active)?(active_input):(dead_input); - if (panel == mouse_panel){ + if (panel == mouse_panel && !mouse_data.out_of_window){ input.mouse = mouse_data; } if (view_->do_view(system, exchange, view_, panel->inner, active_view, diff --git a/4ed.h b/4ed.h index cef626f7..9bf823d5 100644 --- a/4ed.h +++ b/4ed.h @@ -1,205 +1,211 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.12.2014 - * - * Application Layer for 4coder - * - */ - -// TOP - -#ifndef FRED_H -#define FRED_H - -struct Application_Memory{ - void *vars_memory; - i32 vars_memory_size; - void *target_memory; - i32 target_memory_size; -}; - -#define KEY_INPUT_BUFFER_SIZE 4 -#define KEY_INPUT_BUFFER_DSIZE (KEY_INPUT_BUFFER_SIZE << 1) - -enum Key_Control{ - CONTROL_KEY_SHIFT, - CONTROL_KEY_CONTROL, - CONTROL_KEY_ALT, - CONTROL_KEY_CAPS, - // always last - CONTROL_KEY_COUNT -}; - -struct Key_Event_Data{ - u8 keycode; - u8 character; - u8 character_no_caps_lock; - - b8 modifiers[CONTROL_KEY_COUNT]; -}; - -struct Key_Input_Data{ - Key_Event_Data press[KEY_INPUT_BUFFER_SIZE]; - Key_Event_Data hold[KEY_INPUT_BUFFER_SIZE]; - i32 press_count; - i32 hold_count; -}; - -struct Key_Summary{ - i32 count; - Key_Event_Data keys[KEY_INPUT_BUFFER_DSIZE]; -}; - -inline Key_Event_Data -get_single_key(Key_Summary *summary, i32 index){ - Assert(index >= 0 && index < summary->count); - Key_Event_Data key; - key = summary->keys[index]; - return key; -} - -struct Mouse_State{ - b32 out_of_window; - b8 left_button, right_button; - b8 left_button_pressed, right_button_pressed; - b8 left_button_released, right_button_released; - i16 wheel; - i32 x, y; -}; - -struct Mouse_Summary{ - i32 mx, my; - b32 l, r; - b32 press_l, press_r; - b32 release_l, release_r; - b32 out_of_window; - b32 wheel_used; - i16 wheel_amount; -}; - -struct Input_Summary{ - Mouse_Summary mouse; - Key_Summary keys; - Key_Codes *codes; -}; - -// TODO(allen): This can go, and we can just use a String for it. -struct Clipboard_Contents{ - u8 *str; - i32 size; -}; - -#define FileNameMax (1 << 9) - -struct File_Slot{ - File_Slot *next, *prev; - byte *data; - i32 size, max; - char *filename; - i32 filename_len; - u32 flags; -}; - -enum File_Exchange_Flag{ - FEx_Request = 0x1, - FEx_Ready = 0x2, - FEx_Not_Exist = 0x4, - FEx_Save = 0x8, - FEx_Save_Complete = 0x10 -}; - -struct File_Exchange{ - File_Slot available, active, free_list; - File_Slot *files; - i32 num_active, max; -}; - -struct Exchange{ - Thread_Exchange thread; - File_Exchange file; -}; - -struct Command_Line_Parameters{ - char **argv; - int argc; -}; - -struct App_Plat_Settings{ - char *custom_dll; - b32 custom_dll_is_strict; -}; - -#define App_Read_Command_Line_Sig(name) \ - i32 name(System_Functions *system, \ - Application_Memory *memory, \ - String current_directory, \ - Command_Line_Parameters clparams \ - ) - -typedef App_Read_Command_Line_Sig(App_Read_Command_Line); - -#define App_Init_Sig(name) void \ - name(System_Functions *system, \ - Render_Target *target, \ - Application_Memory *memory, \ - Exchange *exchange, \ - Key_Codes *codes, \ - Clipboard_Contents clipboard, \ - String current_directory, \ - Custom_API api) - -typedef App_Init_Sig(App_Init); - -enum Application_Mouse_Cursor{ - APP_MOUSE_CURSOR_DEFAULT, - APP_MOUSE_CURSOR_ARROW, - APP_MOUSE_CURSOR_IBEAM, - APP_MOUSE_CURSOR_LEFTRIGHT, - APP_MOUSE_CURSOR_UPDOWN, - // never below this - APP_MOUSE_CURSOR_COUNT -}; - -struct Application_Step_Result{ - Application_Mouse_Cursor mouse_cursor_type; - b32 redraw; - b32 lctrl_lalt_is_altgr; -}; - -#define App_Step_Sig(name) void \ - name(System_Functions *system, \ - Key_Codes *codes, \ - Key_Input_Data *input, \ - Mouse_State *mouse, \ - Render_Target *target, \ - Application_Memory *memory, \ - Exchange *exchange, \ - Clipboard_Contents clipboard, \ - b32 time_step, b32 first_step, b32 force_redraw, \ - Application_Step_Result *result) - -typedef App_Step_Sig(App_Step); - -#define App_Alloc_Sig(name) void *name(void *handle, i32 size) -typedef App_Alloc_Sig(App_Alloc); - -#define App_Free_Sig(name) void name(void *handle, void *block) -typedef App_Free_Sig(App_Free); - -struct App_Functions{ - App_Read_Command_Line *read_command_line; - App_Init *init; - App_Step *step; - - App_Alloc *alloc; - App_Free *free; -}; - -#define App_Get_Functions_Sig(name) App_Functions name() -typedef App_Get_Functions_Sig(App_Get_Functions); - -#endif - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.12.2014 + * + * Application Layer for 4coder + * + */ + +// TOP + +#ifndef FRED_H +#define FRED_H + +struct Application_Memory{ + void *vars_memory; + i32 vars_memory_size; + void *target_memory; + i32 target_memory_size; +}; + +#define KEY_INPUT_BUFFER_SIZE 4 +#define KEY_INPUT_BUFFER_DSIZE (KEY_INPUT_BUFFER_SIZE << 1) + +enum Key_Control{ + CONTROL_KEY_SHIFT, + CONTROL_KEY_CONTROL, + CONTROL_KEY_ALT, + CONTROL_KEY_CAPS, + // always last + CONTROL_KEY_COUNT +}; + +struct Key_Event_Data{ + u8 keycode; + u8 character; + u8 character_no_caps_lock; + + b8 modifiers[CONTROL_KEY_COUNT]; +}; + +struct Key_Input_Data{ + Key_Event_Data press[KEY_INPUT_BUFFER_SIZE]; + Key_Event_Data hold[KEY_INPUT_BUFFER_SIZE]; + i32 press_count; + i32 hold_count; +}; + +struct Key_Summary{ + i32 count; + Key_Event_Data keys[KEY_INPUT_BUFFER_DSIZE]; +}; + +inline Key_Event_Data +get_single_key(Key_Summary *summary, i32 index){ + Assert(index >= 0 && index < summary->count); + Key_Event_Data key; + key = summary->keys[index]; + return key; +} + +struct Mouse_State{ + b32 out_of_window; + b8 left_button, right_button; + b8 left_button_pressed, right_button_pressed; + b8 left_button_released, right_button_released; + i16 wheel; + i32 x, y; +}; + +struct Mouse_Summary{ + i32 mx, my; + b32 l, r; + b32 press_l, press_r; + b32 release_l, release_r; + b32 out_of_window; + b32 wheel_used; + i16 wheel_amount; +}; + +struct Input_Summary{ + Mouse_Summary mouse; + Key_Summary keys; + Key_Codes *codes; +}; + +// TODO(allen): This can go, and we can just use a String for it. +struct Clipboard_Contents{ + u8 *str; + i32 size; +}; + +#define FileNameMax (1 << 9) + +struct File_Slot{ + File_Slot *next, *prev; + byte *data; + i32 size, max; + char *filename; + i32 filename_len; + u32 flags; +}; + +enum File_Exchange_Flag{ + FEx_Request = 0x1, + FEx_Ready = 0x2, + FEx_Not_Exist = 0x4, + FEx_Save = 0x8, + FEx_Save_Complete = 0x10 +}; + +struct File_Exchange{ + File_Slot available, active, free_list; + File_Slot *files; + i32 num_active, max; +}; + +struct Exchange{ + Thread_Exchange thread; + File_Exchange file; +}; + +struct Command_Line_Parameters{ + char **argv; + int argc; +}; + +struct Plat_Settings{ + char *custom_dll; + b32 custom_dll_is_strict; + + i32 window_w, window_h; + i32 window_x, window_y; + b8 set_window_pos, set_window_size; + b8 maximize_window; +}; + +#define App_Read_Command_Line_Sig(name) \ + i32 name(System_Functions *system, \ + Application_Memory *memory, \ + String current_directory, \ + Plat_Settings *plat_settings, \ + Command_Line_Parameters clparams \ + ) + +typedef App_Read_Command_Line_Sig(App_Read_Command_Line); + +#define App_Init_Sig(name) void \ + name(System_Functions *system, \ + Render_Target *target, \ + Application_Memory *memory, \ + Exchange *exchange, \ + Key_Codes *codes, \ + Clipboard_Contents clipboard, \ + String current_directory, \ + Custom_API api) + +typedef App_Init_Sig(App_Init); + +enum Application_Mouse_Cursor{ + APP_MOUSE_CURSOR_DEFAULT, + APP_MOUSE_CURSOR_ARROW, + APP_MOUSE_CURSOR_IBEAM, + APP_MOUSE_CURSOR_LEFTRIGHT, + APP_MOUSE_CURSOR_UPDOWN, + // never below this + APP_MOUSE_CURSOR_COUNT +}; + +struct Application_Step_Result{ + Application_Mouse_Cursor mouse_cursor_type; + b32 redraw; + b32 lctrl_lalt_is_altgr; +}; + +#define App_Step_Sig(name) void \ + name(System_Functions *system, \ + Key_Codes *codes, \ + Key_Input_Data *input, \ + Mouse_State *mouse, \ + Render_Target *target, \ + Application_Memory *memory, \ + Exchange *exchange, \ + Clipboard_Contents clipboard, \ + b32 time_step, b32 first_step, b32 force_redraw, \ + Application_Step_Result *result) + +typedef App_Step_Sig(App_Step); + +#define App_Alloc_Sig(name) void *name(void *handle, i32 size) +typedef App_Alloc_Sig(App_Alloc); + +#define App_Free_Sig(name) void name(void *handle, void *block) +typedef App_Free_Sig(App_Free); + +struct App_Functions{ + App_Read_Command_Line *read_command_line; + App_Init *init; + App_Step *step; + + App_Alloc *alloc; + App_Free *free; +}; + +#define App_Get_Functions_Sig(name) App_Functions name() +typedef App_Get_Functions_Sig(App_Get_Functions); + +#endif + +// BOTTOM + diff --git a/4ed_app_settings.h b/4ed_app_settings.h index 3c32db29..248d4bd7 100644 --- a/4ed_app_settings.h +++ b/4ed_app_settings.h @@ -1,25 +1,25 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 27.01.2016 - * - * Global app level settings definition - * - */ - -// TOP - -struct App_Settings{ - char *user_file; - b32 user_file_is_strict; - - char *init_files[4]; - i32 init_files_count; - i32 init_files_max; - - i32 initial_line; - b32 lctrl_lalt_is_altgr; -}; - -// BOTTOM - +/* + * Mr. 4th Dimention - Allen Webster + * + * 27.01.2016 + * + * Global app level settings definition + * + */ + +// TOP + +struct App_Settings{ + char *user_file; + b32 user_file_is_strict; + + char *init_files[8]; + i32 init_files_count; + i32 init_files_max; + + i32 initial_line; + b32 lctrl_lalt_is_altgr; +}; + +// BOTTOM + diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 4b733079..e6d20a58 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -99,6 +99,7 @@ struct Editing_File_Settings{ Font_Set *set; i32 base_map_id; i32 dos_write_mode; + b32 unwrapped_lines; b8 tokens_exist; b8 super_locked; b8 is_initialized; @@ -1111,7 +1112,8 @@ struct File_View{ f32 scroll_y, target_y, vel_y; f32 scroll_x, target_x, vel_x; f32 preferred_x; - Full_Cursor scroll_y_cursor; + i32 scroll_i; + union{ Incremental_Search isearch; struct{ @@ -1220,21 +1222,26 @@ file_save(System_Functions *system, Exchange *exchange, Mem_Options *mem, i32 result = 0; #if BUFFER_EXPERIMENT_SCALPEL <= 3 - i32 max = buffer_size(&file->state.buffer) + file->state.buffer.line_count; - byte *data = (byte*)general_memory_allocate(&mem->general, max, 0); - Assert(data); - i32 size; - if (file->settings.dos_write_mode){ - size = buffer_convert_out(&file->state.buffer, (char*)data, max); - } - else{ - size = buffer_size(&file->state.buffer); - buffer_stringify(&file->state.buffer, 0, size, (char*)data); - } + i32 max, size; + byte *data; + b32 dos_write_mode = file->settings.dos_write_mode; + if (dos_write_mode) + max = buffer_size(&file->state.buffer) + file->state.buffer.line_count + 1; + else + max = buffer_size(&file->state.buffer); + + data = (byte*)general_memory_allocate(&mem->general, max, 0); + Assert(data); + + if (dos_write_mode) + size = buffer_convert_out(&file->state.buffer, (char*)data, max); + else + buffer_stringify(&file->state.buffer, 0, size = max, (char*)data); + i32 filename_len = str_size(filename); result = exchange_save_file(exchange, filename, filename_len, - data, size, max); + data, size, max); if (result == 0){ general_memory_free(&mem->general, data); @@ -2293,6 +2300,7 @@ view_set_file(System_Functions *system, File_View *view, view->font_advance = info->advance; view->font_height = info->height; view->font_set = set; + view->unwrapped_lines = file->settings.unwrapped_lines; file->settings.set = set; view->cursor = {}; @@ -2647,6 +2655,83 @@ file_pre_edit_maintenance(System_Functions *system, file->state.last_4ed_edit_time = system->time(); } +struct Cursor_Fix_Descriptor{ + b32 is_batch; + union{ + struct{ + Buffer_Edit *batch; + i32 batch_size; + }; + struct{ + i32 start, end; + i32 shift_amount; + }; + }; +}; + +internal void +file_edit_cursor_fix(System_Functions *system, + Partition *part, General_Memory *general, + Editing_File *file, Editing_Layout *layout, + Cursor_Fix_Descriptor desc){ + Full_Cursor temp_cursor; + Temp_Memory cursor_temp = begin_temp_memory(part); + i32 cursor_max = layout->panel_max_count * 2; + Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); + + i32 panel_count = layout->panel_count; + i32 cursor_count = 0; + Panel *current_panel = layout->panels; + for (i32 i = 0; i < panel_count; ++i, ++current_panel){ + File_View *current_view = view_to_file_view(current_panel->view); + if (current_view && current_view->file == file){ + view_measure_wraps(system, general, current_view); + write_cursor_with_index(cursors, &cursor_count, current_view->cursor.pos); + write_cursor_with_index(cursors, &cursor_count, current_view->mark); + write_cursor_with_index(cursors, &cursor_count, current_view->scroll_i); + } + } + + if (cursor_count > 0){ + buffer_sort_cursors(cursors, cursor_count); + if (desc.is_batch){ + buffer_batch_edit_update_cursors(cursors, cursor_count, + desc.batch, desc.batch_size); + } + else{ + buffer_update_cursors(cursors, cursor_count, + desc.start, desc.end, + desc.shift_amount + (desc.end - desc.start)); + + } + buffer_unsort_cursors(cursors, cursor_count); + + cursor_count = 0; + current_panel = layout->panels; + for (i32 i = 0; i < panel_count; ++i, ++current_panel){ + File_View *current_view = view_to_file_view(current_panel->view); + if (current_view && current_view->file == file){ + view_cursor_move(current_view, cursors[cursor_count++].pos); + current_view->preferred_x = view_get_cursor_x(current_view); + + current_view->mark = cursors[cursor_count++].pos; + current_view->scroll_i = cursors[cursor_count++].pos; + temp_cursor = view_compute_cursor_from_pos(current_view, current_view->scroll_i); + if (current_view->unwrapped_lines){ + current_view->target_y += (temp_cursor.unwrapped_y - current_view->scroll_y); + current_view->scroll_y = temp_cursor.unwrapped_y; + } + else{ + current_view->target_y += (temp_cursor.wrapped_y - current_view->scroll_y); + current_view->scroll_y = temp_cursor.wrapped_y; + } + } + } + } + + end_temp_memory(cursor_temp); +} + internal void file_do_single_edit(System_Functions *system, Mem_Options *mem, Editing_File *file, @@ -2722,40 +2807,14 @@ file_do_single_edit(System_Functions *system, #endif #if BUFFER_EXPERIMENT_SCALPEL <= 3 - Temp_Memory cursor_temp = begin_temp_memory(&mem->part); - i32 cursor_max = layout->panel_max_count * 2; - Cursor_With_Index *cursors = push_array(&mem->part, Cursor_With_Index, cursor_max); + Cursor_Fix_Descriptor desc = {}; + desc.start = start; + desc.end = end; + desc.shift_amount = shift_amount; - i32 cursor_count = 0; - current_panel = layout->panels; - for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - File_View *current_view = view_to_file_view(current_panel->view); - if (current_view && current_view->file == file){ - view_measure_wraps(system, general, current_view); - write_cursor_with_index(cursors, &cursor_count, current_view->cursor.pos); - write_cursor_with_index(cursors, &cursor_count, current_view->mark); - } - } + file_edit_cursor_fix(system, part, general, + file, layout, desc); - if (cursor_count > 0){ - buffer_sort_cursors(cursors, cursor_count); - buffer_update_cursors(cursors, cursor_count, - start, end, shift_amount + (end - start)); - buffer_unsort_cursors(cursors, cursor_count); - } - - cursor_count = 0; - current_panel = layout->panels; - for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - File_View *current_view = view_to_file_view(current_panel->view); - if (current_view && current_view->file == file){ - view_cursor_move(current_view, cursors[cursor_count++].pos); - current_view->mark = cursors[cursor_count++].pos; - current_view->preferred_x = view_get_cursor_x(current_view); - } - } - - end_temp_memory(cursor_temp); #endif } @@ -2834,41 +2893,14 @@ view_do_white_batch_edit(System_Functions *system, Mem_Options *mem, File_View * } // NOTE(allen): cursor fixing - { - Temp_Memory cursor_temp = begin_temp_memory(part); - i32 cursor_max = layout->panel_max_count * 2; - Cursor_With_Index *cursors = push_array(part, Cursor_With_Index, cursor_max); + Cursor_Fix_Descriptor desc = {}; + desc.is_batch = 1; + desc.batch = batch; + desc.batch_size = batch_size; - i32 panel_count = layout->panel_count; - i32 cursor_count = 0; - Panel *current_panel = layout->panels; - for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - File_View *current_view = view_to_file_view(current_panel->view); - if (current_view && current_view->file == file){ - view_measure_wraps(system, general, current_view); - write_cursor_with_index(cursors, &cursor_count, current_view->cursor.pos); - write_cursor_with_index(cursors, &cursor_count, current_view->mark); - } - } + file_edit_cursor_fix(system, part, general, + file, layout, desc); - if (cursor_count > 0){ - buffer_sort_cursors(cursors, cursor_count); - buffer_batch_edit_update_cursors(cursors, cursor_count, batch, batch_size); - buffer_unsort_cursors(cursors, cursor_count); - } - - cursor_count = 0; - current_panel = layout->panels; - for (i32 i = 0; i < panel_count; ++i, ++current_panel){ - File_View *current_view = view_to_file_view(current_panel->view); - if (current_view && current_view->file == file){ - view_cursor_move(current_view, cursors[cursor_count++].pos); - current_view->mark = cursors[cursor_count++].pos; - current_view->preferred_x = view_get_cursor_x(current_view); - } - } - end_temp_memory(cursor_temp); - } #endif } @@ -4168,10 +4200,27 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t if (font) advance_data = font->advance_data; i32 count; + Full_Cursor render_cursor; Buffer_Render_Options opts = {}; - buffer_get_render_data(&file->state.buffer, view->line_wrap_y, items, max, &count, - (f32)rect.x0, (f32)rect.y0, view->scroll_x, view->scroll_y, !view->unwrapped_lines, - (f32)max_x, (f32)max_y, advance_data, (f32)line_height, opts); + + f32 *wraps = view->line_wrap_y; + f32 scroll_x = view->scroll_x; + f32 scroll_y = view->scroll_y; + + { + render_cursor = buffer_get_start_cursor(&file->state.buffer, wraps, scroll_y, + !view->unwrapped_lines, (f32)max_x, advance_data, (f32)line_height); + + view->scroll_i = render_cursor.pos; + + buffer_get_render_data(&file->state.buffer, items, max, &count, + (f32)rect.x0, (f32)rect.y0, + scroll_x, scroll_y, render_cursor, + !view->unwrapped_lines, + (f32)max_x, (f32)max_y, + advance_data, (f32)line_height, + opts); + } Assert(count > 0); @@ -4212,9 +4261,11 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t Buffer_Render_Item *item = items; i32 prev_ind = -1; u32 highlight_color = 0; + u32 highlight_this_color = 0; for (i32 i = 0; i < count; ++i, ++item){ i32 ind = item->index; + highlight_this_color = 0; if (tokens_use && ind != prev_ind){ Cpp_Token current_token = token_stack.tokens[token_i-1]; @@ -4231,23 +4282,39 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t } if (current_token.type == CPP_TOKEN_JUNK && - i >= current_token.start && i <= current_token.start + current_token.size){ + i >= current_token.start && i < current_token.start + current_token.size){ highlight_color = style->main.highlight_junk_color; } + else{ + highlight_color = 0; + } } - u32 char_color = main_color; + u32 char_color = main_color; if (item->flags & BRFlag_Special_Character) char_color = special_color; + + f32_Rect char_rect = f32R(item->x0, item->y0, item->x1, item->y1); + if (view->show_whitespace && highlight_color == 0 && + char_is_whitespace((char)item->glyphid)){ + highlight_this_color = style->main.highlight_white_color; + } + else{ + highlight_this_color = highlight_color; + } if (cursor_begin <= ind && ind < cursor_end && (ind != prev_ind || cursor_begin < ind)){ if (is_active){ - draw_rectangle(target, f32R(item->x0, item->y0, item->x1, item->y1), cursor_color); + draw_rectangle(target, char_rect, cursor_color); char_color = at_cursor_color; } - else draw_rectangle_outline(target, f32R(item->x0, item->y0, item->x1, item->y1), cursor_color); + else{ + if (!view->show_temp_highlight){ + draw_rectangle_outline(target, char_rect, cursor_color); + } + } } - else if (highlight_color){ - draw_rectangle(target, f32R(item->x0, item->y0, item->x1, item->y1), highlight_color); + else if (highlight_this_color){ + draw_rectangle(target, char_rect, highlight_this_color); } u32 fade_color = 0xFFFF00FF; @@ -4263,7 +4330,7 @@ draw_file_loaded(File_View *view, i32_Rect rect, b32 is_active, Render_Target *t char_color = color_blend(char_color, fade_amount, fade_color); if (ind == view->mark && prev_ind != ind){ - draw_rectangle_outline(target, f32R(item->x0, item->y0, item->x1, item->y1), mark_color); + draw_rectangle_outline(target, char_rect, mark_color); } if (item->glyphid != 0){ font_draw_glyph(target, font_id, (u8)item->glyphid, diff --git a/4ed_linux_keyboard.cpp b/4ed_linux_keyboard.cpp index 58cd726c..3296e8ed 100644 --- a/4ed_linux_keyboard.cpp +++ b/4ed_linux_keyboard.cpp @@ -14,28 +14,19 @@ internal void keycode_init(Key_Codes *codes){ set_dynamic_key_names(codes); - - u16 code, loose; - for (u16 i = 0; i < 255; ++i){ - if (i >= 'a' && i <= 'z'){ - keycode_lookup_table[i] = i + ('A' - 'a'); - loose_keycode_lookup_table[i] = 0; - } - - else if (i >= '0' && i <= '9'){ - keycode_lookup_table[i] = i; - loose_keycode_lookup_table[i] = 0; - } - - else{ - loose = 0; - switch (i){ - } - - keycode_lookup_table[i] = code; - loose_keycode_lookup_table[i] = loose; - } - } + + keycode_lookup_table[KEY_BACKSPACE] = codes->back; + keycode_lookup_table[KEY_DELETE] = codes->del; + keycode_lookup_table[KEY_UP] = codes->up; + keycode_lookup_table[KEY_DOWN] = codes->down; + keycode_lookup_table[KEY_LEFT] = codes->left; + keycode_lookup_table[KEY_RIGHT] = codes->right; + keycode_lookup_table[KEY_INSERT] = codes->insert; + keycode_lookup_table[KEY_HOME] = codes->home; + keycode_lookup_table[KEY_END] = codes->end; + keycode_lookup_table[KEY_PAGEUP] = codes->page_up; + keycode_lookup_table[KEY_PAGEDOWN] = codes->page_down; + keycode_lookup_table[KEY_ESC] = codes->esc; } // BOTTOM diff --git a/4ed_meta.h b/4ed_meta.h index 50cfc4e9..9455c268 100644 --- a/4ed_meta.h +++ b/4ed_meta.h @@ -112,7 +112,7 @@ _OutDbgStr(u8*); TMax(u8, 255); TMax(u16, 65535); TMax(u32, 4294967295); -TMax(u64, 18446744073709551615); +TMax(u64, 18446744073709551615U); TMax(i8, 127); TMax(i16, 32767); diff --git a/buffer/4coder_buffer_abstract.cpp b/buffer/4coder_buffer_abstract.cpp index 529f8280..41cf2c39 100644 --- a/buffer/4coder_buffer_abstract.cpp +++ b/buffer/4coder_buffer_abstract.cpp @@ -1145,13 +1145,33 @@ struct Buffer_Render_Options{ b8 show_slash_t; }; +internal_4tech Full_Cursor +buffer_get_start_cursor(Buffer_Type *buffer, float *wraps, float scroll_y, + int wrapped, float width, float *advance_data, float font_height){ + Full_Cursor result; + + if (wrapped){ + result = buffer_cursor_from_wrapped_xy(buffer, 0, scroll_y, 0, wraps, + width, font_height, advance_data); + } + else{ + result = buffer_cursor_from_unwrapped_xy(buffer, 0, scroll_y, 0, wraps, + width, font_height, advance_data); + } + + return(result); +} + internal_4tech void -buffer_get_render_data(Buffer_Type *buffer, float *wraps, Buffer_Render_Item *items, int max, int *count, - float port_x, float port_y, float scroll_x, float scroll_y, int wrapped, - float width, float height, float *advance_data, float font_height, +buffer_get_render_data(Buffer_Type *buffer, Buffer_Render_Item *items, int max, int *count, + float port_x, float port_y, + float scroll_x, float scroll_y, Full_Cursor start_cursor, + int wrapped, + float width, float height, + float *advance_data, float font_height, Buffer_Render_Options opts){ + Buffer_Stringify_Type loop; - Full_Cursor start_cursor; Buffer_Render_Item *item; char *data; int size, end; @@ -1160,21 +1180,13 @@ buffer_get_render_data(Buffer_Type *buffer, float *wraps, Buffer_Render_Item *it int i, item_i; float ch_width, ch_width_sub; char ch; - + size = buffer_size(buffer); shift_x = port_x - scroll_x; shift_y = port_y - scroll_y; - if (wrapped){ - start_cursor = buffer_cursor_from_wrapped_xy(buffer, 0, scroll_y, 0, wraps, - width, font_height, advance_data); - shift_y += start_cursor.wrapped_y; - } - else{ - start_cursor = buffer_cursor_from_unwrapped_xy(buffer, 0, scroll_y, 0, wraps, - width, font_height, advance_data); - shift_y += start_cursor.unwrapped_y; - } + if (wrapped) shift_y += start_cursor.wrapped_y; + else shift_y += start_cursor.unwrapped_y; x = shift_x; y = shift_y; diff --git a/build.bat b/build.bat index 8c2f1a31..fee91a9c 100644 --- a/build.bat +++ b/build.bat @@ -1,3 +1,3 @@ @echo off -call "w:\4ed\code\buildsuper.bat" \ No newline at end of file +call "w:\4ed\misc\builddbg.bat" \ No newline at end of file diff --git a/linux_4ed.cpp b/linux_4ed.cpp index 539a8850..7da52ffc 100644 --- a/linux_4ed.cpp +++ b/linux_4ed.cpp @@ -9,50 +9,7 @@ // TOP -#ifdef FRED_NOT_PACKAGE - -#define FRED_INTERNAL 1 -#define FRED_SLOW 1 - -#define FRED_PRINT_DEBUG 1 -#define FRED_PRINT_DEBUG_FILE_LINE 0 -#define FRED_PROFILING 1 -#define FRED_PROFILING_OS 0 -#define FRED_FULL_ERRORS 0 - -#else - -#define FRED_SLOW 0 -#define FRED_INTERNAL 0 - -#define FRED_PRINT_DEBUG 0 -#define FRED_PRINT_DEBUG_FILE_LINE 0 -#define FRED_PROFILING 0 -#define FRED_PROFILING_OS 0 -#define FRED_FULL_ERRORS 0 - -#endif - -#define SOFTWARE_RENDER 0 - -#if FRED_INTERNAL == 0 -# undef FRED_PRINT_DEBUG -# define FRED_PRINT_DEBUG 0 -# undef FRED_PROFILING -# define FRED_PROFILING 0 -# undef FRED_PROFILING_OS -# define FRED_PROFILING_OS 0 -#endif - -#if FRED_PRINT_DEBUG == 0 -# undef FRED_PRINT_DEBUG_FILE_LINE -# define FRED_PRINT_DEBUG_FILE_LINE 0 -# undef FRED_PRINT_DEBUG_FILE_LINE -# define FRED_PROFILING_OS 0 -#endif - -#define FPS 30 -#define frame_useconds (1000000 / FPS) +#include "4ed_config.h" #include "4ed_meta.h" @@ -60,334 +17,480 @@ #include "4cpp_types.h" #define FCPP_STRING_IMPLEMENTATION -#include "4cpp_string.h" +#include "4coder_string.h" #include "4ed_mem.cpp" - #include "4ed_math.cpp" + #include "4coder_custom.h" #include "4ed_system.h" -#include "4ed.h" #include "4ed_rendering.h" - -#include -#include -#include -#include -#include - -#include -#include - -#include +#include "4ed.h" #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "4ed_internal.h" #include "4ed_linux_keyboard.cpp" -#define printe(m) printf("%s:%d: %s\n", __FILE__, __LINE__, #m) +// NOTE(allen): Thanks to Casey for providing the linux OpenGL launcher. +/* TODO(allen): -struct Linux_Vars{ - Key_Codes codes; - Key_Input_Data input; - Mouse_State mouse; - Render_Target target; - Application_Memory mem; - b32 keep_going; - b32 force_redraw; - - Clipboard_Contents clipboard; + 1. get 4coder rendering it's blank self + 2. get input working + (release linux version) + 3. add in extra stuff as it is completed in windows + + */ - void *app_code, *custom; - - System_Functions *system; - App_Functions app; - Config_API config_api; - -}; - -Linux_Vars linuxvars; - -internal -Sys_Get_Memory_Sig(system_get_memory_){ - void *ptr = 0; - i32 prot = PROT_READ | PROT_WRITE; - i32 flags = MAP_PRIVATE | MAP_ANON; - -#if FRED_INTERNAL - ptr = mmap(0, size + sizeof(Sys_Bubble), prot, flags, -1, 0); - - Sys_Bubble *bubble = (Sys_Bubble*)ptr; - bubble->flags = MEM_BUBBLE_SYS_DEBUG; - bubble->line_number = line_number; - bubble->file_name = file_name; - bubble->size = size; - //WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); - insert_bubble(&win32vars.internal_bubble, bubble); - //ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); - ptr = bubble + 1; -#else - ptr = mmap(0, size + sizeof(i32), prot, flags, -1, 0); - - i32 *size_ptr = (i32*)ptr; - *size_ptr = size; - ptr = size_ptr + 1; -#endif - - return ptr; +static bool ctxErrorOccurred = false; +static int XInput2OpCode = 0; +internal int +ctxErrorHandler( Display *dpy, XErrorEvent *ev ) +{ + ctxErrorOccurred = true; + return 0; } -#define system_get_memory(size) system_get_memory_(size, __LINE__, __FILE__) - -internal -Sys_Free_Memory_Sig(system_free_memory){ - if (block){ -#if FRED_INTERNAL - Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; - Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); - //WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); - remove_bubble(bubble); - //ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); - munmap(bubble, bubble->size); -#else - i32 *size_ptr = (i32*)block - 1; - munmap(size_ptr, *size_ptr); -#endif - } -} - -internal -Sys_Time_Sig(system_time){ - i64 result = 0; - struct timespec tp; - if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0){ - result = tp.tv_sec*1000000 + tp.tv_nsec/1000; - } - return result; -} - -internal -Sys_Load_File_Sig(system_load_file){ - File_Data result = {}; - i32 prot = PROT_READ; - i32 flags = MAP_PRIVATE | MAP_ANON; +internal GLXContext +InitializeOpenGLContext(Display *XDisplay, Window XWindow, GLXFBConfig &bestFbc, b32 &IsLegacy) +{ + IsLegacy = false; - struct stat sb; - if (stat(filename, &sb) == 0){ - result.size = sb.st_size; - result.data = system_get_memory(result.size); - if (result.data){ - i32 file = open(filename, O_RDONLY); - i32 result_size = read(file, result.data, result.size); - Assert(result_size == result.size); - close(file); + typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + const char *glxExts = glXQueryExtensionsString(XDisplay, DefaultScreen(XDisplay)); + + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) + glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); + + GLXContext ctx = 0; + ctxErrorOccurred = false; + int (*oldHandler)(Display*, XErrorEvent*) = + XSetErrorHandler(&ctxErrorHandler); + if (!glXCreateContextAttribsARB) + { + printf( "glXCreateContextAttribsARB() not found" + " ... using old-style GLX context\n" ); + ctx = glXCreateNewContext( XDisplay, bestFbc, GLX_RGBA_TYPE, 0, True ); + } + else + { + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; + + printf("\nAttribs: %d %d %d %d %d\n", + context_attribs[0], + context_attribs[1], + context_attribs[2], + context_attribs[3], + context_attribs[4]); + + printf( "Creating context\n" ); + ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0, + True, context_attribs ); + + XSync( XDisplay, False ); + if ( !ctxErrorOccurred && ctx ) + { + printf( "Created GL 4.3 context\n" ); + } + else + { + ctxErrorOccurred = false; + + context_attribs[1] = 4; + context_attribs[3] = 0; + + printf( "Creating context\n" ); + ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0, + True, context_attribs ); + + XSync( XDisplay, False ); + + if ( !ctxErrorOccurred && ctx ) + { + printf( "Created GL 4.0 context\n" ); + } + else + { + context_attribs[1] = 1; + context_attribs[3] = 0; + + ctxErrorOccurred = false; + + printf( "Failed to create GL 4.0 context" + " ... using old-style GLX context\n" ); + ctx = glXCreateContextAttribsARB( XDisplay, bestFbc, 0, + True, context_attribs ); + + IsLegacy = true; + } } } - - return result; -} + + XSync( XDisplay, False ); + XSetErrorHandler( oldHandler ); + + if ( ctxErrorOccurred || !ctx ) + { + printf( "Failed to create an OpenGL context\n" ); + exit(1); + } + + if ( ! glXIsDirect ( XDisplay, ctx ) ) + { + printf( "Indirect GLX rendering context obtained\n" ); + } + else + { + printf( "Direct GLX rendering context obtained\n" ); + } + + printf( "Making context current\n" ); + glXMakeCurrent( XDisplay, XWindow, ctx ); -internal -Sys_Save_File_Sig(system_save_file){ - i32 file = open(filename, O_CREAT | O_WRONLY); - if (!file) return 0; + GLint n; + char *Vendor = (char *)glGetString(GL_VENDOR); + char *Renderer = (char *)glGetString(GL_RENDERER); + char *Version = (char *)glGetString(GL_VERSION); + char *Extensions = (char *)glGetString(GL_EXTENSIONS); - i32 result_size = write(file, data, size); - Assert(result_size == size); + printf("GL_VENDOR: %s\n", Vendor); + printf("GL_RENDERER: %s\n", Renderer); + printf("GL_VERSION: %s\n", Version); + printf("GL_EXTENSIONS: %s\n", Extensions); - close(file); - return 1; + return(ctx); } internal b32 -LinuxLoadAppCode(){ - b32 result = 0; +GLXSupportsModernContexts(Display *XDisplay) +{ + b32 Result = false; - char app_code_file[] = "4ed_app.so"; - i32 app_code_file_len = sizeof(app_code_file) - 1; - - char path[1024]; - i32 size = readlink("/proc/self/exe", path, - 1024 - app_code_file_len - 1); - - for (--size; - path[size] != '/' && size > 0; - --size); - memcpy(path + size + 1, app_code_file, app_code_file_len + 1); - - linuxvars.app_code = 0; - if (linuxvars.app_code){ - result = 1; - linuxvars.app.init = (App_Init*)0; - linuxvars.app.step = (App_Step*)0; - } - else{ - // TODO(allen): initialization failure - printe(app_code); - } - - return result; -} + int GLXMajor, GLXMinor; -internal -Sys_Acquire_Lock_Sig(system_acquire_lock){ - AllowLocal(id); -} - -internal -Sys_Release_Lock_Sig(system_release_lock){ - AllowLocal(id); -} - -internal -Sys_Force_Redraw_Sig(system_force_redraw){ - linuxvars.force_redraw = 1; -} - -internal void -LinuxLoadSystemCode(){ - linuxvars.system->get_memory_full = system_get_memory_; - linuxvars.system->free_memory = system_free_memory; - - linuxvars.system->load_file = system_load_file; - linuxvars.system->save_file = system_save_file; - -#if 0 - linuxvars.system->file_time_stamp = system_file_time_stamp; - linuxvars.system->time_stamp_now = system_time_stamp_now; - linuxvars.system->free_file = system_free_file; - - linuxvars.system->get_current_directory = system_get_current_directory; - linuxvars.system->get_easy_directory = system_get_easy_directory; - - linuxvars.system->get_file_list = system_get_file_list; - linuxvars.system->free_file_list = system_free_file_list; - - linuxvars.system->post_clipboard = system_post_clipboard; - linuxvars.system->time = system_time; - - linuxvars.system->cli_call = system_cli_call; - linuxvars.system->cli_begin_update = system_cli_begin_update; - linuxvars.system->cli_update_step = system_cli_update_step; - linuxvars.system->cli_end_update = system_cli_end_update; - - linuxvars.system->thread_get_id = system_thread_get_id; - linuxvars.system->thread_current_job_id = system_thread_current_job_id; - linuxvars.system->post_job = system_post_job; - linuxvars.system->cancel_job = system_cancel_job; - linuxvars.system->job_is_pending = system_job_is_pending; - linuxvars.system->grow_thread_memory = system_grow_thread_memory; - linuxvars.system->acquire_lock = system_acquire_lock; - linuxvars.system->release_lock = system_release_lock; - - linuxvars.system->force_redraw = system_force_redraw; - - linuxvars.system->internal_sentinel = INTERNAL_system_sentinel; - linuxvars.system->internal_get_thread_states = INTERNAL_get_thread_states; -#endif -} - -internal void -LinuxShowScreen(){ -} - -int main(){ - linuxvars = {}; - - if (!LinuxLoadAppCode()){ - return(1); - } - - System_Functions system_; - System_Functions *system = &system_; - linuxvars.system = system; - LinuxLoadSystemCode(); - + char *XVendor = ServerVendor(XDisplay); + printf("XWindows vendor: %s\n", XVendor); + if(glXQueryVersion(XDisplay, &GLXMajor, &GLXMinor)) { - void *base; -#if FRED_INTERNAL - base = (void*)Mbytes(128); -#else - base = (void*)0; -#endif - - i32 prot = PROT_READ | PROT_WRITE; - i32 flags = MAP_PRIVATE | MAP_ANON; - - linuxvars.mem.vars_memory_size = Mbytes(2); - linuxvars.mem.vars_memory = mmap(base, linuxvars.mem.vars_memory_size, - prot, flags, -1, 0); - -#if FRED_INTERNAL - base = (void*)Mbytes(160); -#else - base = (void*)0; -#endif - - linuxvars.mem.target_memory_size = Mbytes(64); - linuxvars.mem.target_memory = mmap(base, linuxvars.mem.target_memory_size, - prot, flags, -1, 0); - } - - i32 width = 800; - i32 height = 600; - i32 bpp = 24; - - linuxvars.target.width = width; - linuxvars.target.height = height; - - keycode_init(&linuxvars.codes); - - system_acquire_lock(FRAME_LOCK); - b32 first = 1; - linuxvars.keep_going = 1; - i64 timer_start = system_time(); - - for (;linuxvars.keep_going;){ - linuxvars.input = {}; - linuxvars.clipboard = {}; - linuxvars.mouse.wheel = 0; - linuxvars.force_redraw = 0; - - for (;0;){ + printf("GLX version %d.%d\n", GLXMajor, GLXMinor); + if(((GLXMajor == 1 ) && (GLXMinor >= 3)) || + (GLXMajor > 1)) + { + Result = true; } - - linuxvars.mouse.left_button_prev = linuxvars.mouse.left_button; - linuxvars.mouse.right_button_prev = linuxvars.mouse.right_button; - + } + + return(Result); +} + +typedef struct glx_config_result{ + b32 Found; + GLXFBConfig BestConfig; + XVisualInfo BestInfo; +} glx_config_result; + +internal glx_config_result +ChooseGLXConfig(Display *XDisplay, int XScreenIndex) +{ + glx_config_result Result = {0}; + + int DesiredAttributes[] = + { + GLX_X_RENDERABLE , True, + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, + GLX_RENDER_TYPE , GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, + GLX_RED_SIZE , 8, + GLX_GREEN_SIZE , 8, + GLX_BLUE_SIZE , 8, + GLX_ALPHA_SIZE , 8, + GLX_DEPTH_SIZE , 24, + GLX_STENCIL_SIZE , 8, + GLX_DOUBLEBUFFER , True, + //GLX_SAMPLE_BUFFERS , 1, + //GLX_SAMPLES , 4, + None + }; + + { + int ConfigCount; + GLXFBConfig *Configs = glXChooseFBConfig(XDisplay, + XScreenIndex, + DesiredAttributes, + &ConfigCount); + #if 0 - Application_Step_Result app_result = - linuxvars.app.step(linuxvars.system, - &linuxvars.codes, - &linuxvars.input, - &linuxvars.mouse, - &linuxvars.target, - &linuxvars.mem, - linuxvars.clipboard, - 1, first, linuxvars.force_redraw); -#else - Application_Step_Result app_result = {}; + int DiffValues[GLXValueCount]; #endif - - if (1 || linuxvars.force_redraw){ - //glClearColor(1.f, 1.f, 0.f, 1.f); - //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - LinuxShowScreen(); - linuxvars.force_redraw = 0; - } - - i64 timer_target = timer_start + frame_useconds; - i64 timer_end = system_time(); - for (;timer_end < timer_target;){ - i64 samount = timer_target - timer_end; - usleep(samount); - timer_end = system_time(); - } - timer_start = system_time(); + {for(int ConfigIndex = 0; + ConfigIndex < ConfigCount; + ++ConfigIndex) + { + GLXFBConfig &Config = Configs[ConfigIndex]; + XVisualInfo *VisualInfo = glXGetVisualFromFBConfig(XDisplay, Config); + +#if 0 + printf(" Option %d:\n", ConfigIndex); + printf(" Depth: %d\n", VisualInfo->depth); + printf(" Bits per channel: %d\n", VisualInfo->bits_per_rgb); + printf(" Mask: R%06x G%06x B%06x\n", + (uint32)VisualInfo->red_mask, + (uint32)VisualInfo->green_mask, + (uint32)VisualInfo->blue_mask); + printf(" Class: %d\n", VisualInfo->c_class); +#endif + +#if 0 + {for(int ValueIndex = 0; + ValueIndex < GLXValueCount; + ++ValueIndex) + { + glx_value_info &ValueInfo = GLXValues[ValueIndex]; + int Value; + glXGetFBConfigAttrib(XDisplay, Config, ValueInfo.ID, &Value); + if(DiffValues[ValueIndex] != Value) + { + printf(" %s: %d\n", ValueInfo.Name, Value); + DiffValues[ValueIndex] = Value; + } + }} +#endif + + // TODO(casey): How the hell are you supposed to pick a config here?? + if(ConfigIndex == 0) + { + Result.Found = true; + Result.BestConfig = Config; + Result.BestInfo = *VisualInfo; + } + + XFree(VisualInfo); + }} + + XFree(Configs); } + + return(Result); +} + +internal void +InitializeXInput(Display *dpy, Window XWindow) +{ + int event, error; + if(XQueryExtension(dpy, "XInputExtension", &XInput2OpCode, &event, &error)) + { + int major = 2, minor = 0; + if(XIQueryVersion(dpy, &major, &minor) != BadRequest) + { + printf("XInput initialized"); + } + else + { + printf("XI2 not available. Server supports %d.%d\n", major, minor); + } + } + else + { + printf("X Input extension not available.\n"); + } + + /* + TODO(casey): So, this is all one big clusterfuck I guess. + + The problem here is that you want to be able to get input + from all possible devices that could be a mouse or keyboard + (or gamepad, or whatever). So you'd like to be able to + register events for XIAllDevices, so that when a new + input device is connected, you will start receiving + input from it automatically, without having to periodically + poll XIQueryDevice to see if a new device has appeared. + + UNFORTUNATELY, this is not actually possible in Linux because + there was a bug in Xorg (as of early 2013, it is still not + fixed in most distributions people are using, AFAICT) which + makes the XServer return an error if you actually try to + do this :( + + But EVENTUALLY, if that shit gets fixed, then that is + the way this should work. + */ + +#if 0 + int DeviceCount; + XIDeviceInfo *DeviceInfo = XIQueryDevice(dpy, XIAllDevices, &DeviceCount); + {for(int32x DeviceIndex = 0; + DeviceIndex < DeviceCount; + ++DeviceIndex) + { + XIDeviceInfo *Device = DeviceInfo + DeviceIndex; + printf("Device %d: %s\n", Device->deviceid, Device->name); + }} + XIFreeDeviceInfo(DeviceInfo); +#endif - return(0); + XIEventMask Mask = {0}; + Mask.deviceid = XIAllDevices; + Mask.mask_len = XIMaskLen(XI_RawMotion); + size_t MaskSize = Mask.mask_len * sizeof(char unsigned); + Mask.mask = (char unsigned *)alloca(MaskSize); + memset(Mask.mask, 0, MaskSize); + if(Mask.mask) + { + XISetMask(Mask.mask, XI_ButtonPress); + XISetMask(Mask.mask, XI_ButtonRelease); + XISetMask(Mask.mask, XI_KeyPress); + XISetMask(Mask.mask, XI_KeyRelease); + XISetMask(Mask.mask, XI_Motion); + XISetMask(Mask.mask, XI_DeviceChanged); + XISetMask(Mask.mask, XI_Enter); + XISetMask(Mask.mask, XI_Leave); + XISetMask(Mask.mask, XI_FocusIn); + XISetMask(Mask.mask, XI_FocusOut); + XISetMask(Mask.mask, XI_HierarchyChanged); + XISetMask(Mask.mask, XI_PropertyEvent); + XISelectEvents(dpy, XWindow, &Mask, 1); + XSync(dpy, False); + + Mask.deviceid = XIAllMasterDevices; + memset(Mask.mask, 0, MaskSize); + XISetMask(Mask.mask, XI_RawKeyPress); + XISetMask(Mask.mask, XI_RawKeyRelease); + XISetMask(Mask.mask, XI_RawButtonPress); + XISetMask(Mask.mask, XI_RawButtonRelease); + XISetMask(Mask.mask, XI_RawMotion); + XISelectEvents(dpy, DefaultRootWindow(dpy), &Mask, 1); + } +} + +int +main(int ArgCount, char **Args) +{ + Display *XDisplay = XOpenDisplay(0); + if(XDisplay && GLXSupportsModernContexts(XDisplay)) + { + int XScreenCount = ScreenCount(XDisplay); + for(int XScreenIndex = 0; + XScreenIndex < XScreenCount; + ++XScreenIndex) + { + Screen *XScreen = ScreenOfDisplay(XDisplay, XScreenIndex); + + int WinWidth = WidthOfScreen(XScreen); + int WinHeight = HeightOfScreen(XScreen); + + glx_config_result Config = ChooseGLXConfig(XDisplay, XScreenIndex); + if(Config.Found) + { + Colormap cmap; + XSetWindowAttributes swa; + swa.colormap = cmap = XCreateColormap(XDisplay, + RootWindow(XDisplay, Config.BestInfo.screen ), + Config.BestInfo.visual, AllocNone); + swa.background_pixmap = None; + swa.border_pixel = 0; + swa.event_mask = StructureNotifyMask; + + Window XWindow = XCreateWindow(XDisplay, + RootWindow(XDisplay, Config.BestInfo.screen), + 0, 0, WinWidth, WinHeight, + 0, Config.BestInfo.depth, InputOutput, + Config.BestInfo.visual, + CWBorderPixel|CWColormap|CWEventMask, &swa ); + if(XWindow) + { + XStoreName(XDisplay, XWindow, "4coder"); + XMapWindow(XDisplay, XWindow); + + InitializeXInput(XDisplay, XWindow); + + b32 IsLegacy = false; + GLXContext GLContext = + InitializeOpenGLContext(XDisplay, XWindow, Config.BestConfig, IsLegacy); + + XWindowAttributes WinAttribs; + if(XGetWindowAttributes(XDisplay, XWindow, &WinAttribs)) + { + WinWidth = WinAttribs.width; + WinHeight = WinAttribs.height; + } + + XRaiseWindow(XDisplay, XWindow); + XSync(XDisplay, False); + + for(;;) + { + while(XPending(XDisplay)) + { + XEvent Event; + XNextEvent(XDisplay, &Event); + + if((Event.xcookie.type == GenericEvent) && + (Event.xcookie.extension == XInput2OpCode) && + XGetEventData(XDisplay, &Event.xcookie)) + { + switch(Event.xcookie.evtype) + { + case XI_Motion: + { + Window root_return, child_return; + int root_x_return, root_y_return; + int MouseX, MouseY; + unsigned int mask_return; + XQueryPointer(XDisplay, + XWindow, + &root_return, &child_return, + &root_x_return, &root_y_return, + &MouseX, &MouseY, + &mask_return); + } break; + + case XI_ButtonPress: + case XI_ButtonRelease: + { + b32 Down = (Event.xcookie.evtype == XI_ButtonPress); + XIDeviceEvent *DevEvent = (XIDeviceEvent *)Event.xcookie.data; + int Button = DevEvent->detail; + } break; + + case XI_KeyPress: + case XI_KeyRelease: + { + b32 Down = (Event.xcookie.evtype == XI_KeyPress); + XIDeviceEvent *DevEvent = (XIDeviceEvent *)Event.xcookie.data; + int VK = DevEvent->detail; + } break; + } + + XFreeEventData(XDisplay, &Event.xcookie); + } + } + + // Draw some stuff here? + + glXSwapBuffers(XDisplay, XWindow); + } + } + } + } + } } // BOTTOM diff --git a/vc120.pdb b/vc120.pdb index fee3ca2b..b4fb3e2e 100644 Binary files a/vc120.pdb and b/vc120.pdb differ diff --git a/win32_4ed.cpp b/win32_4ed.cpp index 5e3346e9..650705ff 100644 --- a/win32_4ed.cpp +++ b/win32_4ed.cpp @@ -1,1821 +1,1849 @@ -/* - * Mr. 4th Dimention - Allen Webster - * - * 12.12.2014 - * - * Win32 layer for project codename "4ed" - * - */ - -// TOP - -#include "4ed_config.h" - -#include "4ed_meta.h" - -#define FCPP_FORBID_MALLOC - -#include "4cpp_types.h" -#define FCPP_STRING_IMPLEMENTATION -#include "4coder_string.h" - -#include "4ed_mem.cpp" -#include "4ed_math.cpp" - -#include "4ed_dll_reader.h" -#include "4coder_custom.h" -#include "4ed_system.h" -#include "4ed_rendering.h" -#include "4ed.h" - -#include -#include - -#include "4ed_dll_reader.cpp" -#include "4ed_internal.h" -#include "4ed_win32_keyboard.cpp" - -#define FPS 30 -#define frame_useconds (1000000 / FPS) - -#define WM_4coder_LOAD_FONT (WM_USER + 1) -#define WM_4coder_PAINT (WM_USER + 2) -#define WM_4coder_SET_CURSOR (WM_USER + 3) - -struct Thread_Context{ - u32 job_id; - b32 running; - - Work_Queue *queue; - u32 id; - u32 windows_id; - HANDLE handle; -}; - -struct Thread_Group{ - Thread_Context *threads; - i32 count; -}; - -#define UseWinDll 1 -#define UseThreadMemory 1 - -struct Control_Keys{ - b8 l_ctrl; - b8 r_ctrl; - b8 l_alt; - b8 r_alt; -}; - -struct Win32_Input_Chunk_Transient{ - Key_Input_Data key_data; - - b8 mouse_l_press, mouse_l_release; - b8 mouse_r_press, mouse_r_release; - b32 out_of_window; - i16 mouse_wheel; -}; - -struct Win32_Input_Chunk_Persistent{ - i32 mouse_x, mouse_y; - b8 mouse_l, mouse_r; - - b8 keep_playing; - - Control_Keys controls; - b8 control_keys[CONTROL_KEY_COUNT]; -}; - -struct Win32_Input_Chunk{ - Win32_Input_Chunk_Transient trans; - Win32_Input_Chunk_Persistent pers; -}; - -struct Win32_Font_Load_Parameters{ - Win32_Font_Load_Parameters *next; - Win32_Font_Load_Parameters *prev; - - Render_Font *font_out; - char *filename; - i32 pt_size; - i32 tab_width; -}; - - -struct Win32_Vars{ - HWND window_handle; - HDC window_hdc; - Render_Target target; - - HANDLE update_loop_thread; - DWORD update_loop_thread_id; - - Key_Codes key_codes; - Win32_Input_Chunk input_chunk; - b32 lctrl_lalt_is_altgr; - - HCURSOR cursor_ibeam; - HCURSOR cursor_arrow; - HCURSOR cursor_leftright; - HCURSOR cursor_updown; - Application_Mouse_Cursor prev_mouse_cursor; - Clipboard_Contents clipboard_contents; - b32 next_clipboard_is_self; - DWORD clipboard_sequence; - - Thread_Group groups[THREAD_GROUP_COUNT]; - HANDLE locks[LOCK_COUNT]; - HANDLE DEBUG_sysmem_lock; - -#if UseThreadMemory - Thread_Memory *thread_memory; -#endif - - u64 performance_frequency; - u64 start_pcount; - u64 start_time; - -#if UseWinDll - HMODULE app_code; - HMODULE custom; -#else - DLL_Loaded app_dll; - DLL_Loaded custom_dll; -#endif - - System_Functions *system; - App_Functions app; - Custom_API custom_api; - b32 first; - -#if FRED_INTERNAL - Sys_Bubble internal_bubble; -#endif - - Win32_Font_Load_Parameters fnt_params[8]; - Win32_Font_Load_Parameters used_font_param; - Win32_Font_Load_Parameters free_font_param; - Partition fnt_part; - -}; - -globalvar Win32_Vars win32vars; -globalvar Application_Memory memory_vars; -globalvar Exchange exchange_vars; - -#if FRED_INTERNAL -internal Bubble* -INTERNAL_system_sentinel(){ - return (&win32vars.internal_bubble); -} - -internal void -INTERNAL_system_debug_message(char *message){ - OutputDebugString(message); -} - -#endif - -internal void* -Win32GetMemory_(i32 size, i32 line_number, char *file_name){ - void *ptr = 0; - -#if FRED_INTERNAL - ptr = VirtualAlloc(0, size + sizeof(Sys_Bubble), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); - - Sys_Bubble *bubble = (Sys_Bubble*)ptr; - bubble->flags = MEM_BUBBLE_SYS_DEBUG; - bubble->line_number = line_number; - bubble->file_name = file_name; - bubble->size = size; - WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); - insert_bubble(&win32vars.internal_bubble, bubble); - ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); - ptr = bubble + 1; -#else - ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); -#endif - - return ptr; -} - -#define Win32GetMemory(size) Win32GetMemory_(size, __LINE__, __FILE__) - -internal void -Win32FreeMemory(void *block){ - if (block){ -#if FRED_INTERNAL - Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; - Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); - WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); - remove_bubble(bubble); - ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); - VirtualFree(bubble, 0, MEM_RELEASE); -#else - VirtualFree(block, 0, MEM_RELEASE); -#endif - } -} - -internal Partition -Win32ScratchPartition(i32 size){ - Partition part; - void *data; - data = Win32GetMemory(size); - part = partition_open(data, size); - return(part); -} - -internal void -Win32ScratchPartitionGrow(Partition *part, i32 new_size){ - void *data; - if (new_size > part->max){ - data = Win32GetMemory(new_size); - memcpy(data, part->base, part->pos); - Win32FreeMemory(part->base); - part->base = (u8*)data; - } -} - -internal void -Win32ScratchPartitionDouble(Partition *part){ - Win32ScratchPartitionGrow(part, part->max*2); -} - -inline void -system_free_memory(void *block){ - Win32FreeMemory(block); -} - -internal Data -system_load_file(char *filename){ - Data result = {}; - HANDLE file; - file = CreateFile((char*)filename, GENERIC_READ, 0, 0, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (!file || file == INVALID_HANDLE_VALUE){ - return result; - } - - DWORD lo, hi; - lo = GetFileSize(file, &hi); - - if (hi != 0){ - CloseHandle(file); - return result; - } - - result.size = (lo) + (((u64)hi) << 32); - result.data = (byte*)Win32GetMemory(result.size); - - if (!result.data){ - CloseHandle(file); - result = {}; - return result; - } - - DWORD read_size; - BOOL read_result = ReadFile(file, result.data, result.size, - &read_size, 0); - if (!read_result || read_size != (u32)result.size){ - CloseHandle(file); - Win32FreeMemory(result.data); - result = {}; - return result; - } - - CloseHandle(file); - return result; -} - -#include "4ed_rendering.cpp" - -internal b32 -system_save_file(char *filename, void *data, i32 size){ - HANDLE file; - file = CreateFile((char*)filename, GENERIC_WRITE, 0, 0, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - - if (!file || file == INVALID_HANDLE_VALUE){ - return 0; - } - - BOOL write_result; - DWORD bytes_written; - write_result = WriteFile(file, data, size, &bytes_written, 0); - - CloseHandle(file); - - if (!write_result || bytes_written != (u32)size){ - return 0; - } - - return 1; -} - -internal -Sys_File_Time_Stamp_Sig(system_file_time_stamp){ - u64 result; - result = 0; - - FILETIME last_write; - WIN32_FILE_ATTRIBUTE_DATA data; - if (GetFileAttributesEx((char*)filename, GetFileExInfoStandard, &data)){ - last_write = data.ftLastWriteTime; - - result = ((u64)last_write.dwHighDateTime << 32) | (last_write.dwLowDateTime); - result /= 10; - } - - return result; -} - -internal -Sys_Time_Sig(system_time){ - u64 result = 0; - LARGE_INTEGER time; - if (QueryPerformanceCounter(&time)){ - result = (u64)(time.QuadPart - win32vars.start_pcount) * 1000000 / win32vars.performance_frequency; - result += win32vars.start_time; - } - return result; -} - -internal -Sys_Set_File_List_Sig(system_set_file_list){ - if (directory.size > 0){ - char dir_space[MAX_PATH + 32]; - String dir = make_string(dir_space, 0, MAX_PATH + 32); - append(&dir, directory); - char trail_str[] = "\\*"; - append(&dir, trail_str); - - char *c_str_dir = make_c_str(dir); - - WIN32_FIND_DATA find_data; - HANDLE search; - search = FindFirstFileA(c_str_dir, &find_data); - - if (search != INVALID_HANDLE_VALUE){ - i32 count = 0; - i32 file_count = 0; - BOOL more_files = 1; - do{ - if (!match(find_data.cFileName, ".") && - !match(find_data.cFileName, "..")){ - ++file_count; - i32 size = 0; - for(;find_data.cFileName[size];++size); - count += size + 1; - } - more_files = FindNextFile(search, &find_data); - }while(more_files); - FindClose(search); - - i32 required_size = count + file_count * sizeof(File_Info); - if (file_list->block_size < required_size){ - if (file_list->block){ - Win32FreeMemory(file_list->block); - } - - file_list->block = Win32GetMemory(required_size); - } - - file_list->infos = (File_Info*)file_list->block; - char *name = (char*)(file_list->infos + file_count); - if (file_list->block){ - search = FindFirstFileA(c_str_dir, &find_data); - - if (search != INVALID_HANDLE_VALUE){ - File_Info *info = file_list->infos; - more_files = 1; - do{ - if (!match(find_data.cFileName, ".") && - !match(find_data.cFileName, "..")){ - info->folder = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; - info->filename.str = name; - - char *name_base = name; - i32 i = 0; - for(;find_data.cFileName[i];++i) *name++ = find_data.cFileName[i]; - info->filename.size = (i32)(name - name_base); - info->filename.memory_size = info->filename.size + 1; - *name++ = 0; - ++info; - } - more_files = FindNextFile(search, &find_data); - }while(more_files); - FindClose(search); - - file_list->count = file_count; - - }else{ - Win32FreeMemory(file_list->block); - file_list->block = 0; - file_list->block_size = 0; - } - } - } - } -} - -internal -DIRECTORY_HAS_FILE_SIG(system_directory_has_file){ - char *full_filename; - char space[1024]; - HANDLE file; - b32 result; - i32 len; - - full_filename = 0; - len = str_size(filename); - if (dir.memory_size - dir.size - 1 >= len){ - full_filename = dir.str; - memcpy(dir.str + dir.size, filename, len + 1); - } - else if (dir.size + len + 1 < 1024){ - full_filename = space; - memcpy(full_filename, dir.str, dir.size); - memcpy(full_filename + dir.size, filename, len + 1); - } - - result = 0; - if (full_filename){ - file = CreateFile((char*)full_filename, GENERIC_READ, 0, 0, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (file != INVALID_HANDLE_VALUE){ - CloseHandle(file); - result = 1; - } - dir.str[dir.size] = 0; - } - - return(result); -} - -b32 Win32DirectoryExists(char *path){ - DWORD attrib = GetFileAttributesA(path); - return (attrib != INVALID_FILE_ATTRIBUTES && - (attrib & FILE_ATTRIBUTE_DIRECTORY)); -} - -internal -DIRECTORY_CD_SIG(system_directory_cd){ - b32 result = 0; - i32 old_size; - i32 len; - - if (rel_path[0] != 0){ - if (rel_path[0] == '.' && rel_path[1] == 0){ - result = 1; - } - else if (rel_path[0] == '.' && rel_path[1] == '.' && rel_path[2] == 0){ - result = remove_last_folder(dir); - terminate_with_null(dir); - } - else{ - len = str_size(rel_path); - if (dir->size + len + 1 > dir->memory_size){ - old_size = dir->size; - append_partial(dir, rel_path); - append_partial(dir, "\\"); - if (Win32DirectoryExists(dir->str)){ - result = 1; - } - else{ - dir->size = old_size; - } - } - } - } - - return(result); -} - -internal -Sys_Post_Clipboard_Sig(system_post_clipboard){ - if (OpenClipboard(win32vars.window_handle)){ - EmptyClipboard(); - HANDLE memory_handle; - memory_handle = GlobalAlloc(GMEM_MOVEABLE, str.size+1); - if (memory_handle){ - char *dest = (char*)GlobalLock(memory_handle); - copy_fast_unsafe(dest, str); - GlobalUnlock(memory_handle); - SetClipboardData(CF_TEXT, memory_handle); - win32vars.next_clipboard_is_self = 1; - } - CloseClipboard(); - } -} - -internal -Sys_Acquire_Lock_Sig(system_acquire_lock){ - WaitForSingleObject(win32vars.locks[id], INFINITE); -} - -internal -Sys_Release_Lock_Sig(system_release_lock){ - ReleaseSemaphore(win32vars.locks[id], 1, 0); -} - -internal void -Win32RedrawScreen(HDC hdc){ - system_acquire_lock(RENDER_LOCK); - launch_rendering(&win32vars.target); - system_release_lock(RENDER_LOCK); - glFlush(); - SwapBuffers(hdc); -} - -internal void -Win32RedrawFromUpdate(){ - SendMessage( - win32vars.window_handle, - WM_4coder_PAINT, - 0, 0); -} - -internal void -Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ - SendMessage( - win32vars.window_handle, - WM_4coder_SET_CURSOR, - cursor, 0); -} - -internal void -Win32Resize(i32 width, i32 height){ - if (width > 0 && height > 0){ - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, -1, 1); - glScissor(0, 0, width, height); - - win32vars.target.width = width; - win32vars.target.height = height; - } -} - -internal HANDLE -Win32Handle(Plat_Handle h){ - HANDLE result; - result = {}; - result = *(HANDLE*)(&h); - return(result); -} - -internal Plat_Handle -Win32GenHandle(HANDLE h){ - Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); - Plat_Handle result; - result = *(Plat_Handle*)(&h); - return(result); -} - -internal DWORD WINAPI -ThreadProc(LPVOID lpParameter){ - Thread_Context *thread = (Thread_Context*)lpParameter; - Work_Queue *queue = thread->queue; - - for (;;){ - u32 read_index = queue->read_position; - u32 write_index = queue->write_position; - - if (read_index != write_index){ - u32 next_read_index = (read_index + 1) % JOB_ID_WRAP; - u32 safe_read_index = - InterlockedCompareExchange(&queue->read_position, - next_read_index, read_index); - - if (safe_read_index == read_index){ - Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP); - // NOTE(allen): This is interlocked so that it plays nice - // with the cancel job routine, which may try to cancel this job - // at the same time that we try to run it - - i32 safe_running_thread = - InterlockedCompareExchange(&full_job->running_thread, - thread->id, THREAD_NOT_ASSIGNED); - - if (safe_running_thread == THREAD_NOT_ASSIGNED){ - thread->job_id = full_job->id; - thread->running = 1; -#if UseThreadMemory - Thread_Memory *thread_memory = 0; -#endif - - // TODO(allen): remove memory_request - if (full_job->job.memory_request != 0){ -#if UseThreadMemory - thread_memory = win32vars.thread_memory + thread->id - 1; - if (thread_memory->size < full_job->job.memory_request){ - if (thread_memory->data){ - Win32FreeMemory(thread_memory->data); - } - i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); - thread_memory->data = Win32GetMemory(new_size); - thread_memory->size = new_size; - } -#endif - } - full_job->job.callback(win32vars.system, thread, thread_memory, - &exchange_vars.thread, full_job->job.data); - full_job->running_thread = 0; - thread->running = 0; - } - } - } - else{ - WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE); - } - } -} - -internal -Sys_Post_Job_Sig(system_post_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; - - Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); - - b32 success = 0; - u32 result = 0; - while (!success){ - u32 write_index = queue->write_position; - u32 next_write_index = (write_index + 1) % JOB_ID_WRAP; - u32 safe_write_index = - InterlockedCompareExchange(&queue->write_position, - next_write_index, write_index); - if (safe_write_index == write_index){ - result = write_index; - write_index = write_index % QUEUE_WRAP; - queue->jobs[write_index].job = job; - queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED; - queue->jobs[write_index].id = result; - success = 1; - } - } - - ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0); - - return result; -} - -internal -Sys_Cancel_Job_Sig(system_cancel_job){ - Work_Queue *queue = exchange_vars.thread.queues + group_id; - Thread_Group *group = win32vars.groups + group_id; - - u32 job_index; - u32 thread_id; - Full_Job_Data *full_job; - Thread_Context *thread; - - job_index = job_id % QUEUE_WRAP; - full_job = queue->jobs + job_index; - - Assert(full_job->id == job_id); - thread_id = - InterlockedCompareExchange(&full_job->running_thread, - 0, THREAD_NOT_ASSIGNED); - - if (thread_id != THREAD_NOT_ASSIGNED){ - system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); - thread = group->threads + thread_id - 1; - TerminateThread(thread->handle, 0); - u32 creation_flag = 0; - thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); - system_release_lock(CANCEL_LOCK0 + thread_id - 1); - thread->running = 0; - } -} - -#if UseThreadMemory -internal void -system_grow_thread_memory(Thread_Memory *memory){ - system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); - void *old_data = memory->data; - i32 old_size = memory->size; - i32 new_size = LargeRoundUp(memory->size*2, Kbytes(4)); - memory->data = Win32GetMemory(new_size); - memory->size = new_size; - if (old_data){ - memcpy(memory->data, old_data, old_size); - Win32FreeMemory(old_data); - } - system_release_lock(CANCEL_LOCK0 + memory->id - 1); -} -#endif - -#if FRED_INTERNAL -internal void -INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ - Work_Queue *queue = exchange_vars.thread.queues + id; - u32 write = queue->write_position; - u32 read = queue->read_position; - if (write < read) write += JOB_ID_WRAP; - *pending = (i32)(write - read); - - Thread_Group *group = win32vars.groups + id; - for (i32 i = 0; i < group->count; ++i){ - running[i] = (group->threads[i].running != 0); - } -} -#endif - -internal -Sys_CLI_Call_Sig(system_cli_call){ - char cmd[] = "c:\\windows\\system32\\cmd.exe"; - char *env_variables = 0; - char command_line[2048]; - - b32 success = 1; - String s = make_fixed_width_string(command_line); - copy(&s, make_lit_string("/C ")); - append_partial(&s, script_name); - success = terminate_with_null(&s); - - if (success){ - success = 0; - - SECURITY_ATTRIBUTES sec_attributes; - HANDLE out_read; - HANDLE out_write; - - sec_attributes = {}; - sec_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); - sec_attributes.bInheritHandle = TRUE; - - if (CreatePipe(&out_read, &out_write, &sec_attributes, 0)){ - if (SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)){ - STARTUPINFO startup = {}; - startup.cb = sizeof(STARTUPINFO); - startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; - startup.hStdError = out_write; - startup.hStdOutput = out_write; - startup.wShowWindow = SW_HIDE; - - PROCESS_INFORMATION info = {}; - - Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); - if (CreateProcess(cmd, command_line, - 0, 0, TRUE, 0, - env_variables, path, - &startup, &info)){ - success = 1; - CloseHandle(info.hThread); - *(HANDLE*)&cli_out->proc = info.hProcess; - *(HANDLE*)&cli_out->out_read = out_read; - *(HANDLE*)&cli_out->out_write = out_write; - } - else{ - CloseHandle(out_read); - CloseHandle(out_write); - *(HANDLE*)&cli_out->proc = INVALID_HANDLE_VALUE; - *(HANDLE*)&cli_out->out_read = INVALID_HANDLE_VALUE; - *(HANDLE*)&cli_out->out_write = INVALID_HANDLE_VALUE; - } - } - else{ - // TODO(allen): failed SetHandleInformation - } - } - else{ - // TODO(allen): failed CreatePipe - } - } - - return success; -} - -struct CLI_Loop_Control{ - u32 remaining_amount; -}; - -internal -Sys_CLI_Begin_Update_Sig(system_cli_begin_update){ - Assert(sizeof(cli->scratch_space) >= sizeof(CLI_Loop_Control)); - CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; - loop->remaining_amount = 0; -} - -internal -Sys_CLI_Update_Step_Sig(system_cli_update_step){ - HANDLE handle = *(HANDLE*)&cli->out_read; - CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; - b32 has_more = 0; - DWORD remaining = loop->remaining_amount; - u32 pos = 0; - DWORD read_amount = 0; - - for (;;){ - if (remaining == 0){ - if (!PeekNamedPipe(handle, 0, 0, 0, &remaining, 0)) break; - if (remaining == 0) break; - } - - if (remaining + pos < max){ - has_more = 1; - ReadFile(handle, dest + pos, remaining, &read_amount, 0); - TentativeAssert(remaining == read_amount); - pos += remaining; - remaining = 0; - } - else{ - has_more = 1; - ReadFile(handle, dest + pos, max - pos, &read_amount, 0); - TentativeAssert(max - pos == read_amount); - loop->remaining_amount = remaining - (max - pos); - pos = max; - break; - } - } - *amount = pos; - - return has_more; -} - -internal -Sys_CLI_End_Update_Sig(system_cli_end_update){ - b32 close_me = 0; - HANDLE proc = *(HANDLE*)&cli->proc; - DWORD result = 0; - - if (WaitForSingleObject(proc, 0) == WAIT_OBJECT_0){ - if (GetExitCodeProcess(proc, &result) == 0) - cli->exit = -1; - else - cli->exit = (i32)result; - - close_me = 1; - CloseHandle(*(HANDLE*)&cli->proc); - CloseHandle(*(HANDLE*)&cli->out_read); - CloseHandle(*(HANDLE*)&cli->out_write); - } - return close_me; -} - -internal void -fnt__remove(Win32_Font_Load_Parameters *params){ - params->next->prev = params->prev; - params->prev->next = params->next; -} - -internal void -fnt__insert(Win32_Font_Load_Parameters *pos, Win32_Font_Load_Parameters *params){ - params->next = pos->next; - pos->next->prev = params; - pos->next = params; - params->prev = pos; -} - -internal -Font_Load_Sig(system_draw_font_load){ - Win32_Font_Load_Parameters *params; - - system_acquire_lock(FONT_LOCK); - params = win32vars.free_font_param.next; - fnt__remove(params); - fnt__insert(&win32vars.used_font_param, params); - system_release_lock(FONT_LOCK); - - params->font_out = font_out; - params->filename = filename; - params->pt_size = pt_size; - params->tab_width = tab_width; - - SendMessage(win32vars.window_handle, - WM_4coder_LOAD_FONT, - 0, (i32)(params - win32vars.fnt_params)); - return(1); -} - -internal b32 -Win32LoadAppCode(){ - b32 result = 0; - -#if UseWinDll - win32vars.app_code = LoadLibraryA("4ed_app.dll"); - if (win32vars.app_code){ - result = 1; - App_Get_Functions *get_funcs = (App_Get_Functions*) - GetProcAddress(win32vars.app_code, "app_get_functions"); - - win32vars.app = get_funcs(); - } - -#else - Data file = system_load_file("4ed_app.dll"); - - if (file.data){ - i32 error; - DLL_Data dll_data; - if (dll_parse_headers(file, &dll_data, &error)){ - Data img; - img.size = dll_total_loaded_size(&dll_data); - img.data = (byte*) - VirtualAlloc((LPVOID)Tbytes(3), img.size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - - dll_load(img, &win32vars.app_dll, file, &dll_data); - - DWORD extra_; - VirtualProtect(img.data + win32vars.app_dll.text_start, - win32vars.app_dll.text_size, - PAGE_EXECUTE_READ, - &extra_); - - result = 1; - App_Get_Functions *get_functions = (App_Get_Functions*) - dll_load_function(&win32vars.app_dll, "app_get_functions", 17); - } - else{ - // TODO(allen): file loading error - } - - system_free(file.data); - - DUMP((byte*)(Tbytes(3)), Kbytes(400)); - } - else{ - // TODO(allen): file loading error - } - -#endif - - return result; -} - -internal void -Win32LoadSystemCode(){ - win32vars.system->file_time_stamp = system_file_time_stamp; - win32vars.system->set_file_list = system_set_file_list; - - win32vars.system->directory_has_file = system_directory_has_file; - win32vars.system->directory_cd = system_directory_cd; - - win32vars.system->post_clipboard = system_post_clipboard; - win32vars.system->time = system_time; - - win32vars.system->cli_call = system_cli_call; - win32vars.system->cli_begin_update = system_cli_begin_update; - win32vars.system->cli_update_step = system_cli_update_step; - win32vars.system->cli_end_update = system_cli_end_update; - - win32vars.system->post_job = system_post_job; - win32vars.system->cancel_job = system_cancel_job; - win32vars.system->grow_thread_memory = system_grow_thread_memory; - win32vars.system->acquire_lock = system_acquire_lock; - win32vars.system->release_lock = system_release_lock; - - win32vars.system->internal_sentinel = INTERNAL_system_sentinel; - win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; - win32vars.system->internal_debug_message = INTERNAL_system_debug_message; -} - -void -ex__file_insert(File_Slot *pos, File_Slot *file){ - file->next = pos->next; - file->next->prev = file; - file->prev = pos; - pos->next = file; -} - -void -ex__insert_range(File_Slot *start, File_Slot *end, File_Slot *pos){ - end->next->prev = start->prev; - start->prev->next = end->next; - - end->next = pos->next; - start->prev = pos; - pos->next->prev = end; - pos->next = start; -} - -internal void -ex__check_file(File_Slot *pos){ - File_Slot *file = pos; - - Assert(pos == pos->next->prev); - - for (pos = pos->next; - file != pos; - pos = pos->next){ - Assert(pos == pos->next->prev); - } -} - -internal void -ex__check(File_Exchange *file_exchange){ - ex__check_file(&file_exchange->available); - ex__check_file(&file_exchange->active); - ex__check_file(&file_exchange->free_list); -} - -internal LRESULT -Win32Callback(HWND hwnd, UINT uMsg, - WPARAM wParam, LPARAM lParam){ - LRESULT result = {}; - switch (uMsg){ - case WM_MENUCHAR: - case WM_SYSCHAR:break; - - case WM_SYSKEYDOWN: - case WM_SYSKEYUP: - case WM_KEYDOWN: - case WM_KEYUP: - { - switch (wParam){ - case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL: - case VK_MENU:case VK_LMENU:case VK_RMENU: - case VK_SHIFT:case VK_LSHIFT:case VK_RSHIFT: - { - Control_Keys *controls = 0; - b8 *control_keys = 0; - controls = &win32vars.input_chunk.pers.controls; - control_keys = win32vars.input_chunk.pers.control_keys; - - system_acquire_lock(INPUT_LOCK); - - b8 down = ((lParam & Bit_31)?(0):(1)); - b8 is_right = ((lParam & Bit_24)?(1):(0)); - - if (wParam != 255){ - switch (wParam){ - case VK_SHIFT: - { - control_keys[CONTROL_KEY_SHIFT] = down; - }break; - - case VK_CONTROL: - { - if (is_right) controls->r_ctrl = down; - else controls->l_ctrl = down; - }break; - - case VK_MENU: - { - if (is_right) controls->r_alt = down; - else controls->l_alt = down; - }break; - } - - b8 ctrl, alt; - ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); - alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); - - if (win32vars.lctrl_lalt_is_altgr){ - if (controls->l_alt && controls->l_ctrl){ - ctrl = 0; - alt = 0; - } - } - - control_keys[CONTROL_KEY_CONTROL] = ctrl; - control_keys[CONTROL_KEY_ALT] = alt; - } - system_release_lock(INPUT_LOCK); - }break; - - default: - b8 previous_state, current_state; - previous_state = ((lParam & Bit_30)?(1):(0)); - current_state = ((lParam & Bit_31)?(0):(1)); - - if (current_state){ - u8 key = keycode_lookup((u8)wParam); - - i32 *count = 0; - Key_Event_Data *data = 0; - b8 *control_keys = 0; - i32 control_keys_size = 0; - - system_acquire_lock(INPUT_LOCK); - if (!previous_state){ - count = &win32vars.input_chunk.trans.key_data.press_count; - data = win32vars.input_chunk.trans.key_data.press; - } - else{ - count = &win32vars.input_chunk.trans.key_data.hold_count; - data = win32vars.input_chunk.trans.key_data.hold; - } - control_keys = win32vars.input_chunk.pers.control_keys; - control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys); - - if (*count < KEY_INPUT_BUFFER_SIZE){ - if (!key){ - UINT vk = (UINT)wParam; - UINT scan = (UINT)((lParam >> 16) & 0x7F); - BYTE state[256]; - WORD x; - int result; - - GetKeyboardState(state); - if (control_keys[CONTROL_KEY_CONTROL] && - !control_keys[CONTROL_KEY_ALT]) - state[VK_CONTROL] = 0; - x = 0; - result = ToAscii(vk, scan, state, &x, 0); - if (result == 1 && x < 128){ - key = (u8)x; - if (key == '\r') key = '\n'; - data[*count].character = key; - - state[VK_CAPITAL] = 0; - x = 0; - result = ToAscii(vk, scan, state, &x, 0); - if (result == 1 && x < 128){ - key = (u8)x; - if (key == '\r') key = '\n'; - data[*count].character_no_caps_lock = key; - data[*count].keycode = key; - } - } - if (result != 1 || x >= 128){ - data[*count].character = 0; - data[*count].character_no_caps_lock = 0; - data[*count].keycode = 0; - } - } - else{ - data[*count].character = 0; - data[*count].character_no_caps_lock = 0; - data[*count].keycode = key; - } - memcpy(data[*count].modifiers, control_keys, control_keys_size); - ++(*count); - } - } - system_release_lock(INPUT_LOCK); - - result = DefWindowProc(hwnd, uMsg, wParam, lParam); - } - }break; - - case WM_INPUT: - - - case WM_MOUSEMOVE: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.mouse_x = LOWORD(lParam); - win32vars.input_chunk.pers.mouse_y = HIWORD(lParam); - system_release_lock(INPUT_LOCK); - }break; - - case WM_MOUSEWHEEL: - { - system_acquire_lock(INPUT_LOCK); - i16 rotation = GET_WHEEL_DELTA_WPARAM(wParam); - if (rotation > 0){ - win32vars.input_chunk.trans.mouse_wheel = 1; - } - else{ - win32vars.input_chunk.trans.mouse_wheel = -1; - } - system_release_lock(INPUT_LOCK); - }break; - - case WM_LBUTTONDOWN: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_l_press = 1; - win32vars.input_chunk.pers.mouse_l = 1; - system_release_lock(INPUT_LOCK); - }break; - - case WM_RBUTTONDOWN: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_r_press = 1; - win32vars.input_chunk.pers.mouse_r = 1; - system_release_lock(INPUT_LOCK); - }break; - - case WM_LBUTTONUP: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_l_release = 1; - win32vars.input_chunk.pers.mouse_l = 0; - system_release_lock(INPUT_LOCK); - }break; - - case WM_RBUTTONUP: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.trans.mouse_r_release = 1; - win32vars.input_chunk.pers.mouse_r = 0; - system_release_lock(INPUT_LOCK); - }break; - - case WM_KILLFOCUS: - case WM_SETFOCUS: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.mouse_l = 0; - win32vars.input_chunk.pers.mouse_r = 0; - - b8 *control_keys = win32vars.input_chunk.pers.control_keys; - for (int i = 0; i < CONTROL_KEY_COUNT; ++i) control_keys[i] = 0; - win32vars.input_chunk.pers.controls = {}; - - system_release_lock(INPUT_LOCK); - }break; - - case WM_SIZE: - { - if (win32vars.target.handle){ - i32 new_width = LOWORD(lParam); - i32 new_height = HIWORD(lParam); - - Win32Resize(new_width, new_height); - } - }break; - - case WM_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - Win32RedrawScreen(hdc); - EndPaint(hwnd, &ps); - - }break; - - case WM_4coder_PAINT: - { - PAINTSTRUCT ps; - HDC hdc = BeginPaint(hwnd, &ps); - Win32RedrawScreen(hdc); - EndPaint(hwnd, &ps); - }break; - - case WM_4coder_SET_CURSOR: - { - switch (wParam){ - case APP_MOUSE_CURSOR_ARROW: - SetCursor(win32vars.cursor_arrow); break; - - case APP_MOUSE_CURSOR_IBEAM: - SetCursor(win32vars.cursor_ibeam); break; - - case APP_MOUSE_CURSOR_LEFTRIGHT: - SetCursor(win32vars.cursor_leftright); break; - - case APP_MOUSE_CURSOR_UPDOWN: - SetCursor(win32vars.cursor_updown); break; - } - }break; - - case WM_CLOSE: // NOTE(allen): I expect WM_CLOSE not WM_DESTROY - case WM_DESTROY: - { - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.keep_playing = 0; - system_release_lock(INPUT_LOCK); - }break; - - case WM_4coder_LOAD_FONT: - { - if (win32vars.fnt_part.base == 0){ - win32vars.fnt_part = Win32ScratchPartition(Mbytes(8)); - } - - Win32_Font_Load_Parameters *params = win32vars.fnt_params + lParam; - - for (b32 success = 0; success == 0;){ - - success = draw_font_load(win32vars.fnt_part.base, - win32vars.fnt_part.max, - params->font_out, - params->filename, - params->pt_size, - params->tab_width); - - if (!success){ - Win32ScratchPartitionDouble(&win32vars.fnt_part); - } - } - - system_acquire_lock(FONT_LOCK); - fnt__remove(params); - fnt__insert(&win32vars.free_font_param, params); - system_release_lock(FONT_LOCK); - }break; - - default: - { - result = DefWindowProc(hwnd, uMsg, wParam, lParam); - }break; - } - return result; -} - -DWORD -UpdateLoop(LPVOID param){ - for (;win32vars.input_chunk.pers.keep_playing;){ - i64 timer_start = system_time(); - - system_acquire_lock(INPUT_LOCK); - Win32_Input_Chunk input_chunk = win32vars.input_chunk; - win32vars.input_chunk.trans = {}; - system_release_lock(INPUT_LOCK); - - input_chunk.pers.control_keys[CONTROL_KEY_CAPS] = GetKeyState(VK_CAPITAL) & 0x1; - - POINT mouse_point; - if (GetCursorPos(&mouse_point) && ScreenToClient(win32vars.window_handle, &mouse_point)){ - if (mouse_point.x < 0 || mouse_point.x >= win32vars.target.width || - mouse_point.y < 0 || mouse_point.y >= win32vars.target.height){ - input_chunk.trans.out_of_window = 1; - } - } - else{ - input_chunk.trans.out_of_window = 1; - } - - win32vars.clipboard_contents = {}; - if (win32vars.clipboard_sequence != 0){ - DWORD new_number = GetClipboardSequenceNumber(); - if (new_number != win32vars.clipboard_sequence){ - win32vars.clipboard_sequence = new_number; - if (win32vars.next_clipboard_is_self){ - win32vars.next_clipboard_is_self = 0; - } - else if (IsClipboardFormatAvailable(CF_TEXT)){ - if (OpenClipboard(win32vars.window_handle)){ - HANDLE clip_data; - clip_data = GetClipboardData(CF_TEXT); - if (clip_data){ - win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); - if (win32vars.clipboard_contents.str){ - win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); - GlobalUnlock(clip_data); - } - } - CloseClipboard(); - } - } - } - } - - u32 redraw = exchange_vars.thread.force_redraw; - if (redraw) exchange_vars.thread.force_redraw = 0; - - Key_Input_Data input_data; - Mouse_State mouse; - Application_Step_Result result; - - input_data = input_chunk.trans.key_data; - mouse.out_of_window = input_chunk.trans.out_of_window; - - mouse.left_button = input_chunk.pers.mouse_l; - mouse.left_button_pressed = input_chunk.trans.mouse_l_press; - mouse.left_button_released = input_chunk.trans.mouse_l_release; - - mouse.right_button = input_chunk.pers.mouse_r; - mouse.right_button_pressed = input_chunk.trans.mouse_r_press; - mouse.right_button_released = input_chunk.trans.mouse_r_release; - - mouse.wheel = input_chunk.trans.mouse_wheel; - - mouse.x = input_chunk.pers.mouse_x; - mouse.y = input_chunk.pers.mouse_y; - - result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; - result.redraw = redraw; - result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; - - win32vars.app.step(win32vars.system, - &win32vars.key_codes, - &input_data, - &mouse, - &win32vars.target, - &memory_vars, - &exchange_vars, - win32vars.clipboard_contents, - 1, win32vars.first, redraw, - &result); - - ProfileStart(OS_frame_out); - - Win32SetCursorFromUpdate(result.mouse_cursor_type); - win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr; - - if (result.redraw) Win32RedrawFromUpdate(); - - win32vars.first = 0; - - ProfileEnd(OS_frame_out); - - ProfileStart(OS_file_process); - { - File_Slot *file; - int d = 0; - - for (file = exchange_vars.file.active.next; - file != &exchange_vars.file.active; - file = file->next){ - ++d; - - if (file->flags & FEx_Save){ - Assert((file->flags & FEx_Request) == 0); - file->flags &= (~FEx_Save); - system_save_file(file->filename, file->data, file->size); - file->flags |= FEx_Save_Complete; - } - - if (file->flags & FEx_Request){ - Assert((file->flags & FEx_Save) == 0); - file->flags &= (~FEx_Request); - Data sysfile = - system_load_file(file->filename); - if (sysfile.data == 0){ - file->flags |= FEx_Not_Exist; - } - else{ - file->flags |= FEx_Ready; - file->data = sysfile.data; - file->size = sysfile.size; - } - } - } - - Assert(d == exchange_vars.file.num_active); - - for (file = exchange_vars.file.free_list.next; - file != &exchange_vars.file.free_list; - file = file->next){ - if (file->data){ - system_free_memory(file->data); - } - } - - if (exchange_vars.file.free_list.next != &exchange_vars.file.free_list){ - ex__insert_range(exchange_vars.file.free_list.next, exchange_vars.file.free_list.prev, - &exchange_vars.file.available); - } - - ex__check(&exchange_vars.file); - } - ProfileEnd(OS_file_process); - - ProfileStart(frame_sleep); - i64 timer_end = system_time(); - i64 end_target = (timer_start + frame_useconds); - - system_release_lock(FRAME_LOCK); - while (timer_end < end_target){ - DWORD samount = (DWORD)((end_target - timer_end) / 1000); - if (samount > 0) Sleep(samount); - timer_end = system_time(); - } - system_acquire_lock(FRAME_LOCK); - timer_start = system_time(); - ProfileEnd(frame_sleep); - } - - return(0); -} - -int -WinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLine, - int nCmdShow){ - win32vars = {}; - exchange_vars = {}; - -#if FRED_INTERNAL - win32vars.internal_bubble.next = &win32vars.internal_bubble; - win32vars.internal_bubble.prev = &win32vars.internal_bubble; - win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; -#endif - - if (!Win32LoadAppCode()){ - // TODO(allen): Failed to load app code, serious problem. - return 99; - } - - System_Functions system_; - System_Functions *system = &system_; - win32vars.system = system; - Win32LoadSystemCode(); - - LPVOID base; -#if FRED_INTERNAL - base = (LPVOID)Tbytes(1); -#else - base = (LPVOID)0; -#endif - - memory_vars.vars_memory_size = Mbytes(2); - memory_vars.vars_memory = VirtualAlloc(base, memory_vars.vars_memory_size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - -#if FRED_INTERNAL - base = (LPVOID)Tbytes(2); -#else - base = (LPVOID)0; -#endif - memory_vars.target_memory_size = Mbytes(512); - memory_vars.target_memory = VirtualAlloc(base, memory_vars.target_memory_size, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE); - - if (!memory_vars.vars_memory){ - return 4; - } - - DWORD required = GetCurrentDirectory(0, 0); - required += 1; - required *= 4; - char *current_directory_mem = (char*)Win32GetMemory(required); - DWORD written = GetCurrentDirectory(required, current_directory_mem); - - String current_directory = make_string(current_directory_mem, written, required); - terminate_with_null(¤t_directory); - - Command_Line_Parameters clparams; - clparams.argv = __argv; - clparams.argc = __argc; - - i32 output_size = - win32vars.app.read_command_line(system, - &memory_vars, - current_directory, - clparams); - if (output_size > 0){ - - } - if (output_size != 0) return 0; - - LARGE_INTEGER lpf; - QueryPerformanceFrequency(&lpf); - win32vars.performance_frequency = lpf.QuadPart; - QueryPerformanceCounter(&lpf); - win32vars.start_pcount = lpf.QuadPart; - - FILETIME filetime; - GetSystemTimeAsFileTime(&filetime); - win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); - win32vars.start_time /= 10; - - keycode_init(&win32vars.key_codes); - -#ifdef FRED_SUPER - win32vars.custom = LoadLibraryA("4coder_custom.dll"); - if (win32vars.custom){ - win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) - GetProcAddress(win32vars.custom, "get_bindings"); - - win32vars.custom_api.set_extra_font = (Set_Extra_Font_Function*) - GetProcAddress(win32vars.custom, "set_extra_font"); - } -#endif - - Thread_Context background[4]; - memset(background, 0, sizeof(background)); - win32vars.groups[BACKGROUND_THREADS].threads = background; - win32vars.groups[BACKGROUND_THREADS].count = ArrayCount(background); - - -#if UseThreadMemory - Thread_Memory thread_memory[ArrayCount(background)]; - win32vars.thread_memory = thread_memory; -#endif - - exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = - Win32GenHandle( - CreateSemaphore(0, 0, win32vars.groups[BACKGROUND_THREADS].count, 0) - ); - - u32 creation_flag = 0; - for (i32 i = 0; i < win32vars.groups[BACKGROUND_THREADS].count; ++i){ - Thread_Context *thread = win32vars.groups[BACKGROUND_THREADS].threads + i; - thread->id = i + 1; - -#if UseThreadMemory - Thread_Memory *memory = win32vars.thread_memory + i; - *memory = {}; - memory->id = thread->id; -#endif - - thread->queue = &exchange_vars.thread.queues[BACKGROUND_THREADS]; - thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); - } - - Assert(win32vars.locks); - for (i32 i = 0; i < LOCK_COUNT; ++i){ - win32vars.locks[i] = CreateSemaphore(0, 1, 1, 0); - } - win32vars.DEBUG_sysmem_lock = CreateSemaphore(0, 1, 1, 0); - - win32vars.cursor_ibeam = LoadCursor(NULL, IDC_IBEAM); - win32vars.cursor_arrow = LoadCursor(NULL, IDC_ARROW); - win32vars.cursor_leftright = LoadCursor(NULL, IDC_SIZEWE); - win32vars.cursor_updown = LoadCursor(NULL, IDC_SIZENS); - win32vars.prev_mouse_cursor = APP_MOUSE_CURSOR_ARROW; - - WNDCLASS window_class = {}; - window_class.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; - window_class.lpfnWndProc = Win32Callback; - window_class.hInstance = hInstance; - window_class.lpszClassName = "4coder-win32-wndclass"; - - if (!RegisterClass(&window_class)){ - return 1; - } - - RECT window_rect = {}; - window_rect.right = 800; - window_rect.bottom = 600; - - if (!AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, false)){ - // TODO(allen): non-fatal diagnostics - } - -#define WINDOW_NAME "4coder-window" - - HWND window_handle = {}; - window_handle = CreateWindowA( - window_class.lpszClassName, - WINDOW_NAME, - WS_OVERLAPPEDWINDOW | WS_VISIBLE, - CW_USEDEFAULT, CW_USEDEFAULT, - window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top, - 0, 0, hInstance, 0); - - if (window_handle == 0){ - return 2; - } - - // TODO(allen): errors? - win32vars.window_handle = window_handle; - HDC hdc = GetDC(window_handle); - win32vars.window_hdc = hdc; - - GetClientRect(window_handle, &window_rect); - -#if 0 - RAWINPUTDEVICE device; - device.usUsagePage = 0x1; - device.usUsage = 0x6; - device.dwFlags = 0; - device.hwndTarget = window_handle; - RegisterRawInputDevices(&device, 1, sizeof(device)); -#endif - - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, - 32, - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 16, - 0, - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 }; - - i32 pixel_format; - pixel_format = ChoosePixelFormat(hdc, &pfd); - SetPixelFormat(hdc, pixel_format, &pfd); - - win32vars.target.handle = hdc; - win32vars.target.context = wglCreateContext(hdc); - wglMakeCurrent(hdc, (HGLRC)win32vars.target.context); - - glEnable(GL_TEXTURE_2D); - glEnable(GL_SCISSOR_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - Win32Resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); - - win32vars.clipboard_sequence = GetClipboardSequenceNumber(); - - if (win32vars.clipboard_sequence == 0){ - system_post_clipboard(make_lit_string("")); - - win32vars.clipboard_sequence = GetClipboardSequenceNumber(); - win32vars.next_clipboard_is_self = 0; - - if (win32vars.clipboard_sequence == 0){ - // TODO(allen): diagnostics - } - } - - else{ - if (IsClipboardFormatAvailable(CF_TEXT)){ - if (OpenClipboard(win32vars.window_handle)){ - HANDLE clip_data; - clip_data = GetClipboardData(CF_TEXT); - if (clip_data){ - win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); - if (win32vars.clipboard_contents.str){ - win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); - GlobalUnlock(clip_data); - } - } - CloseClipboard(); - } - } - } - - win32vars.target.push_clip = draw_push_clip; - win32vars.target.pop_clip = draw_pop_clip; - win32vars.target.push_piece = draw_push_piece; - - win32vars.target.font_set.font_info_load = draw_font_info_load; - win32vars.target.font_set.font_load = system_draw_font_load; - win32vars.target.font_set.release_font = draw_release_font; - - win32vars.target.max = Mbytes(1); - win32vars.target.push_buffer = (byte*)Win32GetMemory(win32vars.target.max); - - File_Slot file_slots[32]; - exchange_vars.file.max = sizeof(file_slots) / sizeof(file_slots[0]); - exchange_vars.file.available = {}; - exchange_vars.file.available.next = &exchange_vars.file.available; - exchange_vars.file.available.prev = &exchange_vars.file.available; - - exchange_vars.file.active = {}; - exchange_vars.file.active.next = &exchange_vars.file.active; - exchange_vars.file.active.prev = &exchange_vars.file.active; - - exchange_vars.file.free_list = {}; - exchange_vars.file.free_list.next = &exchange_vars.file.free_list; - exchange_vars.file.free_list.prev = &exchange_vars.file.free_list; - - exchange_vars.file.files = file_slots; - memset(file_slots, 0, sizeof(file_slots)); - - char *filename_space = (char*) - Win32GetMemory(FileNameMax*exchange_vars.file.max); - - for (int i = 0; i < exchange_vars.file.max; ++i){ - File_Slot *slot = file_slots + i; - ex__file_insert(&exchange_vars.file.available, slot); - slot->filename = filename_space; - filename_space += FileNameMax; - } - - win32vars.free_font_param.next = &win32vars.free_font_param; - win32vars.free_font_param.prev = &win32vars.free_font_param; - - win32vars.used_font_param.next = &win32vars.used_font_param; - win32vars.used_font_param.prev = &win32vars.used_font_param; - - for (i32 i = 0; i < ArrayCount(win32vars.fnt_params); ++i){ - fnt__insert(&win32vars.free_font_param, win32vars.fnt_params + i); - } - - win32vars.app.init(win32vars.system, &win32vars.target, - &memory_vars, &exchange_vars, &win32vars.key_codes, - win32vars.clipboard_contents, current_directory, - win32vars.custom_api); - - win32vars.input_chunk.pers.keep_playing = 1; - win32vars.first = 1; - timeBeginPeriod(1); - - win32vars.update_loop_thread = - CreateThread(0, - 0, - UpdateLoop, - 0, - CREATE_SUSPENDED, - &win32vars.update_loop_thread_id); - - system_acquire_lock(FRAME_LOCK); - - ResumeThread(win32vars.update_loop_thread); - - MSG msg; - for (;win32vars.input_chunk.pers.keep_playing && GetMessage(&msg, 0, 0, 0);){ - if (msg.message == WM_QUIT){ - system_acquire_lock(INPUT_LOCK); - win32vars.input_chunk.pers.keep_playing = 0; - system_release_lock(INPUT_LOCK); - }else{ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return 0; -} - -// BOTTOM - - +/* + * Mr. 4th Dimention - Allen Webster + * + * 12.12.2014 + * + * Win32 layer for project codename "4ed" + * + */ + +// TOP + +#include "4ed_config.h" + +#include "4ed_meta.h" + +#define FCPP_FORBID_MALLOC + +#include "4cpp_types.h" +#define FCPP_STRING_IMPLEMENTATION +#include "4coder_string.h" + +#include "4ed_mem.cpp" +#include "4ed_math.cpp" + +#include "4ed_dll_reader.h" + +#include "4coder_custom.h" +#include "4ed_system.h" +#include "4ed_rendering.h" +#include "4ed.h" + +#include +#include + +#include "4ed_dll_reader.cpp" +#include "4ed_internal.h" +#include "4ed_win32_keyboard.cpp" + +#define FPS 30 +#define frame_useconds (1000000 / FPS) + +#define WM_4coder_LOAD_FONT (WM_USER + 1) +#define WM_4coder_PAINT (WM_USER + 2) +#define WM_4coder_SET_CURSOR (WM_USER + 3) + +struct Thread_Context{ + u32 job_id; + b32 running; + + Work_Queue *queue; + u32 id; + u32 windows_id; + HANDLE handle; +}; + +struct Thread_Group{ + Thread_Context *threads; + i32 count; +}; + +#define UseWinDll 1 +#define UseThreadMemory 1 + +struct Control_Keys{ + b8 l_ctrl; + b8 r_ctrl; + b8 l_alt; + b8 r_alt; +}; + +struct Win32_Input_Chunk_Transient{ + Key_Input_Data key_data; + + b8 mouse_l_press, mouse_l_release; + b8 mouse_r_press, mouse_r_release; + b32 out_of_window; + i16 mouse_wheel; +}; + +struct Win32_Input_Chunk_Persistent{ + i32 mouse_x, mouse_y; + b8 mouse_l, mouse_r; + + b8 keep_playing; + + Control_Keys controls; + b8 control_keys[CONTROL_KEY_COUNT]; +}; + +struct Win32_Input_Chunk{ + Win32_Input_Chunk_Transient trans; + Win32_Input_Chunk_Persistent pers; +}; + +struct Win32_Font_Load_Parameters{ + Win32_Font_Load_Parameters *next; + Win32_Font_Load_Parameters *prev; + + Render_Font *font_out; + char *filename; + i32 pt_size; + i32 tab_width; +}; + + +struct Win32_Vars{ + HWND window_handle; + HDC window_hdc; + Render_Target target; + + HANDLE update_loop_thread; + DWORD update_loop_thread_id; + + Key_Codes key_codes; + Win32_Input_Chunk input_chunk; + b32 lctrl_lalt_is_altgr; + + HCURSOR cursor_ibeam; + HCURSOR cursor_arrow; + HCURSOR cursor_leftright; + HCURSOR cursor_updown; + Application_Mouse_Cursor prev_mouse_cursor; + Clipboard_Contents clipboard_contents; + b32 next_clipboard_is_self; + DWORD clipboard_sequence; + + Thread_Group groups[THREAD_GROUP_COUNT]; + HANDLE locks[LOCK_COUNT]; + HANDLE DEBUG_sysmem_lock; + +#if UseThreadMemory + Thread_Memory *thread_memory; +#endif + + u64 performance_frequency; + u64 start_pcount; + u64 start_time; + +#if UseWinDll + HMODULE app_code; + HMODULE custom; +#else + DLL_Loaded app_dll; + DLL_Loaded custom_dll; +#endif + + Plat_Settings settings; + System_Functions *system; + App_Functions app; + Custom_API custom_api; + b32 first; + +#if FRED_INTERNAL + Sys_Bubble internal_bubble; +#endif + + Win32_Font_Load_Parameters fnt_params[8]; + Win32_Font_Load_Parameters used_font_param; + Win32_Font_Load_Parameters free_font_param; + Partition fnt_part; +}; + +globalvar Win32_Vars win32vars; +globalvar Application_Memory memory_vars; +globalvar Exchange exchange_vars; + +#if FRED_INTERNAL +internal Bubble* +INTERNAL_system_sentinel(){ + return (&win32vars.internal_bubble); +} + +internal void +INTERNAL_system_debug_message(char *message){ + OutputDebugString(message); +} + +#endif + +internal void* +Win32GetMemory_(i32 size, i32 line_number, char *file_name){ + void *ptr = 0; + +#if FRED_INTERNAL + ptr = VirtualAlloc(0, size + sizeof(Sys_Bubble), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + Sys_Bubble *bubble = (Sys_Bubble*)ptr; + bubble->flags = MEM_BUBBLE_SYS_DEBUG; + bubble->line_number = line_number; + bubble->file_name = file_name; + bubble->size = size; + WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); + insert_bubble(&win32vars.internal_bubble, bubble); + ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); + ptr = bubble + 1; +#else + ptr = VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#endif + + return ptr; +} + +#define Win32GetMemory(size) Win32GetMemory_(size, __LINE__, __FILE__) + +internal void +Win32FreeMemory(void *block){ + if (block){ +#if FRED_INTERNAL + Sys_Bubble *bubble = ((Sys_Bubble*)block) - 1; + Assert((bubble->flags & MEM_BUBBLE_DEBUG_MASK) == MEM_BUBBLE_SYS_DEBUG); + WaitForSingleObject(win32vars.DEBUG_sysmem_lock, INFINITE); + remove_bubble(bubble); + ReleaseSemaphore(win32vars.DEBUG_sysmem_lock, 1, 0); + VirtualFree(bubble, 0, MEM_RELEASE); +#else + VirtualFree(block, 0, MEM_RELEASE); +#endif + } +} + +internal Partition +Win32ScratchPartition(i32 size){ + Partition part; + void *data; + data = Win32GetMemory(size); + part = partition_open(data, size); + return(part); +} + +internal void +Win32ScratchPartitionGrow(Partition *part, i32 new_size){ + void *data; + if (new_size > part->max){ + data = Win32GetMemory(new_size); + memcpy(data, part->base, part->pos); + Win32FreeMemory(part->base); + part->base = (u8*)data; + } +} + +internal void +Win32ScratchPartitionDouble(Partition *part){ + Win32ScratchPartitionGrow(part, part->max*2); +} + +inline void +system_free_memory(void *block){ + Win32FreeMemory(block); +} + +internal Data +system_load_file(char *filename){ + Data result = {}; + HANDLE file; + file = CreateFile((char*)filename, GENERIC_READ, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (!file || file == INVALID_HANDLE_VALUE){ + return result; + } + + DWORD lo, hi; + lo = GetFileSize(file, &hi); + + if (hi != 0){ + CloseHandle(file); + return result; + } + + result.size = (lo) + (((u64)hi) << 32); + result.data = (byte*)Win32GetMemory(result.size); + + if (!result.data){ + CloseHandle(file); + result = {}; + return result; + } + + DWORD read_size; + BOOL read_result = ReadFile(file, result.data, result.size, + &read_size, 0); + if (!read_result || read_size != (u32)result.size){ + CloseHandle(file); + Win32FreeMemory(result.data); + result = {}; + return result; + } + + CloseHandle(file); + return result; +} + +#include "4ed_rendering.cpp" + +internal b32 +system_save_file(char *filename, void *data, i32 size){ + HANDLE file; + file = CreateFile((char*)filename, GENERIC_WRITE, 0, 0, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + + if (!file || file == INVALID_HANDLE_VALUE){ + return 0; + } + + BOOL write_result; + DWORD bytes_written; + write_result = WriteFile(file, data, size, &bytes_written, 0); + + CloseHandle(file); + + if (!write_result || bytes_written != (u32)size){ + return 0; + } + + return 1; +} + +internal +Sys_File_Time_Stamp_Sig(system_file_time_stamp){ + u64 result; + result = 0; + + FILETIME last_write; + WIN32_FILE_ATTRIBUTE_DATA data; + if (GetFileAttributesEx((char*)filename, GetFileExInfoStandard, &data)){ + last_write = data.ftLastWriteTime; + + result = ((u64)last_write.dwHighDateTime << 32) | (last_write.dwLowDateTime); + result /= 10; + } + + return result; +} + +internal +Sys_Time_Sig(system_time){ + u64 result = 0; + LARGE_INTEGER time; + if (QueryPerformanceCounter(&time)){ + result = (u64)(time.QuadPart - win32vars.start_pcount) * 1000000 / win32vars.performance_frequency; + result += win32vars.start_time; + } + return result; +} + +internal +Sys_Set_File_List_Sig(system_set_file_list){ + if (directory.size > 0){ + char dir_space[MAX_PATH + 32]; + String dir = make_string(dir_space, 0, MAX_PATH + 32); + append(&dir, directory); + char trail_str[] = "\\*"; + append(&dir, trail_str); + + char *c_str_dir = make_c_str(dir); + + WIN32_FIND_DATA find_data; + HANDLE search; + search = FindFirstFileA(c_str_dir, &find_data); + + if (search != INVALID_HANDLE_VALUE){ + i32 count = 0; + i32 file_count = 0; + BOOL more_files = 1; + do{ + if (!match(find_data.cFileName, ".") && + !match(find_data.cFileName, "..")){ + ++file_count; + i32 size = 0; + for(;find_data.cFileName[size];++size); + count += size + 1; + } + more_files = FindNextFile(search, &find_data); + }while(more_files); + FindClose(search); + + i32 required_size = count + file_count * sizeof(File_Info); + if (file_list->block_size < required_size){ + if (file_list->block){ + Win32FreeMemory(file_list->block); + } + + file_list->block = Win32GetMemory(required_size); + } + + file_list->infos = (File_Info*)file_list->block; + char *name = (char*)(file_list->infos + file_count); + if (file_list->block){ + search = FindFirstFileA(c_str_dir, &find_data); + + if (search != INVALID_HANDLE_VALUE){ + File_Info *info = file_list->infos; + more_files = 1; + do{ + if (!match(find_data.cFileName, ".") && + !match(find_data.cFileName, "..")){ + info->folder = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + info->filename.str = name; + + char *name_base = name; + i32 i = 0; + for(;find_data.cFileName[i];++i) *name++ = find_data.cFileName[i]; + info->filename.size = (i32)(name - name_base); + info->filename.memory_size = info->filename.size + 1; + *name++ = 0; + ++info; + } + more_files = FindNextFile(search, &find_data); + }while(more_files); + FindClose(search); + + file_list->count = file_count; + + }else{ + Win32FreeMemory(file_list->block); + file_list->block = 0; + file_list->block_size = 0; + } + } + } + } +} + +internal +DIRECTORY_HAS_FILE_SIG(system_directory_has_file){ + char *full_filename; + char space[1024]; + HANDLE file; + b32 result; + i32 len; + + full_filename = 0; + len = str_size(filename); + if (dir.memory_size - dir.size - 1 >= len){ + full_filename = dir.str; + memcpy(dir.str + dir.size, filename, len + 1); + } + else if (dir.size + len + 1 < 1024){ + full_filename = space; + memcpy(full_filename, dir.str, dir.size); + memcpy(full_filename + dir.size, filename, len + 1); + } + + result = 0; + if (full_filename){ + file = CreateFile((char*)full_filename, GENERIC_READ, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (file != INVALID_HANDLE_VALUE){ + CloseHandle(file); + result = 1; + } + dir.str[dir.size] = 0; + } + + return(result); +} + +b32 Win32DirectoryExists(char *path){ + DWORD attrib = GetFileAttributesA(path); + return (attrib != INVALID_FILE_ATTRIBUTES && + (attrib & FILE_ATTRIBUTE_DIRECTORY)); +} + +internal +DIRECTORY_CD_SIG(system_directory_cd){ + b32 result = 0; + i32 old_size; + i32 len; + + if (rel_path[0] != 0){ + if (rel_path[0] == '.' && rel_path[1] == 0){ + result = 1; + } + else if (rel_path[0] == '.' && rel_path[1] == '.' && rel_path[2] == 0){ + result = remove_last_folder(dir); + terminate_with_null(dir); + } + else{ + len = str_size(rel_path); + if (dir->size + len + 1 > dir->memory_size){ + old_size = dir->size; + append_partial(dir, rel_path); + append_partial(dir, "\\"); + if (Win32DirectoryExists(dir->str)){ + result = 1; + } + else{ + dir->size = old_size; + } + } + } + } + + return(result); +} + +internal +Sys_Post_Clipboard_Sig(system_post_clipboard){ + if (OpenClipboard(win32vars.window_handle)){ + EmptyClipboard(); + HANDLE memory_handle; + memory_handle = GlobalAlloc(GMEM_MOVEABLE, str.size+1); + if (memory_handle){ + char *dest = (char*)GlobalLock(memory_handle); + copy_fast_unsafe(dest, str); + GlobalUnlock(memory_handle); + SetClipboardData(CF_TEXT, memory_handle); + win32vars.next_clipboard_is_self = 1; + } + CloseClipboard(); + } +} + +internal +Sys_Acquire_Lock_Sig(system_acquire_lock){ + WaitForSingleObject(win32vars.locks[id], INFINITE); +} + +internal +Sys_Release_Lock_Sig(system_release_lock){ + ReleaseSemaphore(win32vars.locks[id], 1, 0); +} + +internal void +Win32RedrawScreen(HDC hdc){ + system_acquire_lock(RENDER_LOCK); + launch_rendering(&win32vars.target); + system_release_lock(RENDER_LOCK); + glFlush(); + SwapBuffers(hdc); +} + +internal void +Win32RedrawFromUpdate(){ + SendMessage( + win32vars.window_handle, + WM_4coder_PAINT, + 0, 0); +} + +internal void +Win32SetCursorFromUpdate(Application_Mouse_Cursor cursor){ + SendMessage( + win32vars.window_handle, + WM_4coder_SET_CURSOR, + cursor, 0); +} + +internal void +Win32Resize(i32 width, i32 height){ + if (width > 0 && height > 0){ + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, -1, 1); + glScissor(0, 0, width, height); + + win32vars.target.width = width; + win32vars.target.height = height; + } +} + +internal HANDLE +Win32Handle(Plat_Handle h){ + HANDLE result; + result = {}; + result = *(HANDLE*)(&h); + return(result); +} + +internal Plat_Handle +Win32GenHandle(HANDLE h){ + Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); + Plat_Handle result; + result = *(Plat_Handle*)(&h); + return(result); +} + +internal DWORD WINAPI +ThreadProc(LPVOID lpParameter){ + Thread_Context *thread = (Thread_Context*)lpParameter; + Work_Queue *queue = thread->queue; + + for (;;){ + u32 read_index = queue->read_position; + u32 write_index = queue->write_position; + + if (read_index != write_index){ + u32 next_read_index = (read_index + 1) % JOB_ID_WRAP; + u32 safe_read_index = + InterlockedCompareExchange(&queue->read_position, + next_read_index, read_index); + + if (safe_read_index == read_index){ + Full_Job_Data *full_job = queue->jobs + (safe_read_index % QUEUE_WRAP); + // NOTE(allen): This is interlocked so that it plays nice + // with the cancel job routine, which may try to cancel this job + // at the same time that we try to run it + + i32 safe_running_thread = + InterlockedCompareExchange(&full_job->running_thread, + thread->id, THREAD_NOT_ASSIGNED); + + if (safe_running_thread == THREAD_NOT_ASSIGNED){ + thread->job_id = full_job->id; + thread->running = 1; +#if UseThreadMemory + Thread_Memory *thread_memory = 0; +#endif + + // TODO(allen): remove memory_request + if (full_job->job.memory_request != 0){ +#if UseThreadMemory + thread_memory = win32vars.thread_memory + thread->id - 1; + if (thread_memory->size < full_job->job.memory_request){ + if (thread_memory->data){ + Win32FreeMemory(thread_memory->data); + } + i32 new_size = LargeRoundUp(full_job->job.memory_request, Kbytes(4)); + thread_memory->data = Win32GetMemory(new_size); + thread_memory->size = new_size; + } +#endif + } + full_job->job.callback(win32vars.system, thread, thread_memory, + &exchange_vars.thread, full_job->job.data); + full_job->running_thread = 0; + thread->running = 0; + } + } + } + else{ + WaitForSingleObject(Win32Handle(queue->semaphore), INFINITE); + } + } +} + +internal +Sys_Post_Job_Sig(system_post_job){ + Work_Queue *queue = exchange_vars.thread.queues + group_id; + + Assert((queue->write_position + 1) % QUEUE_WRAP != queue->read_position % QUEUE_WRAP); + + b32 success = 0; + u32 result = 0; + while (!success){ + u32 write_index = queue->write_position; + u32 next_write_index = (write_index + 1) % JOB_ID_WRAP; + u32 safe_write_index = + InterlockedCompareExchange(&queue->write_position, + next_write_index, write_index); + if (safe_write_index == write_index){ + result = write_index; + write_index = write_index % QUEUE_WRAP; + queue->jobs[write_index].job = job; + queue->jobs[write_index].running_thread = THREAD_NOT_ASSIGNED; + queue->jobs[write_index].id = result; + success = 1; + } + } + + ReleaseSemaphore(Win32Handle(queue->semaphore), 1, 0); + + return result; +} + +internal +Sys_Cancel_Job_Sig(system_cancel_job){ + Work_Queue *queue = exchange_vars.thread.queues + group_id; + Thread_Group *group = win32vars.groups + group_id; + + u32 job_index; + u32 thread_id; + Full_Job_Data *full_job; + Thread_Context *thread; + + job_index = job_id % QUEUE_WRAP; + full_job = queue->jobs + job_index; + + Assert(full_job->id == job_id); + thread_id = + InterlockedCompareExchange(&full_job->running_thread, + 0, THREAD_NOT_ASSIGNED); + + if (thread_id != THREAD_NOT_ASSIGNED){ + system_acquire_lock(CANCEL_LOCK0 + thread_id - 1); + thread = group->threads + thread_id - 1; + TerminateThread(thread->handle, 0); + u32 creation_flag = 0; + thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); + system_release_lock(CANCEL_LOCK0 + thread_id - 1); + thread->running = 0; + } +} + +#if UseThreadMemory +internal void +system_grow_thread_memory(Thread_Memory *memory){ + system_acquire_lock(CANCEL_LOCK0 + memory->id - 1); + void *old_data = memory->data; + i32 old_size = memory->size; + i32 new_size = LargeRoundUp(memory->size*2, Kbytes(4)); + memory->data = Win32GetMemory(new_size); + memory->size = new_size; + if (old_data){ + memcpy(memory->data, old_data, old_size); + Win32FreeMemory(old_data); + } + system_release_lock(CANCEL_LOCK0 + memory->id - 1); +} +#endif + +#if FRED_INTERNAL +internal void +INTERNAL_get_thread_states(Thread_Group_ID id, bool8 *running, i32 *pending){ + Work_Queue *queue = exchange_vars.thread.queues + id; + u32 write = queue->write_position; + u32 read = queue->read_position; + if (write < read) write += JOB_ID_WRAP; + *pending = (i32)(write - read); + + Thread_Group *group = win32vars.groups + id; + for (i32 i = 0; i < group->count; ++i){ + running[i] = (group->threads[i].running != 0); + } +} +#endif + +internal +Sys_CLI_Call_Sig(system_cli_call){ + char cmd[] = "c:\\windows\\system32\\cmd.exe"; + char *env_variables = 0; + char command_line[2048]; + + b32 success = 1; + String s = make_fixed_width_string(command_line); + copy(&s, make_lit_string("/C ")); + append_partial(&s, script_name); + success = terminate_with_null(&s); + + if (success){ + success = 0; + + SECURITY_ATTRIBUTES sec_attributes; + HANDLE out_read; + HANDLE out_write; + + sec_attributes = {}; + sec_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); + sec_attributes.bInheritHandle = TRUE; + + if (CreatePipe(&out_read, &out_write, &sec_attributes, 0)){ + if (SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)){ + STARTUPINFO startup = {}; + startup.cb = sizeof(STARTUPINFO); + startup.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; + startup.hStdError = out_write; + startup.hStdOutput = out_write; + startup.wShowWindow = SW_HIDE; + + PROCESS_INFORMATION info = {}; + + Assert(sizeof(Plat_Handle) >= sizeof(HANDLE)); + if (CreateProcess(cmd, command_line, + 0, 0, TRUE, 0, + env_variables, path, + &startup, &info)){ + success = 1; + CloseHandle(info.hThread); + *(HANDLE*)&cli_out->proc = info.hProcess; + *(HANDLE*)&cli_out->out_read = out_read; + *(HANDLE*)&cli_out->out_write = out_write; + } + else{ + CloseHandle(out_read); + CloseHandle(out_write); + *(HANDLE*)&cli_out->proc = INVALID_HANDLE_VALUE; + *(HANDLE*)&cli_out->out_read = INVALID_HANDLE_VALUE; + *(HANDLE*)&cli_out->out_write = INVALID_HANDLE_VALUE; + } + } + else{ + // TODO(allen): failed SetHandleInformation + } + } + else{ + // TODO(allen): failed CreatePipe + } + } + + return success; +} + +struct CLI_Loop_Control{ + u32 remaining_amount; +}; + +internal +Sys_CLI_Begin_Update_Sig(system_cli_begin_update){ + Assert(sizeof(cli->scratch_space) >= sizeof(CLI_Loop_Control)); + CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; + loop->remaining_amount = 0; +} + +internal +Sys_CLI_Update_Step_Sig(system_cli_update_step){ + HANDLE handle = *(HANDLE*)&cli->out_read; + CLI_Loop_Control *loop = (CLI_Loop_Control*)cli->scratch_space; + b32 has_more = 0; + DWORD remaining = loop->remaining_amount; + u32 pos = 0; + DWORD read_amount = 0; + + for (;;){ + if (remaining == 0){ + if (!PeekNamedPipe(handle, 0, 0, 0, &remaining, 0)) break; + if (remaining == 0) break; + } + + if (remaining + pos < max){ + has_more = 1; + ReadFile(handle, dest + pos, remaining, &read_amount, 0); + TentativeAssert(remaining == read_amount); + pos += remaining; + remaining = 0; + } + else{ + has_more = 1; + ReadFile(handle, dest + pos, max - pos, &read_amount, 0); + TentativeAssert(max - pos == read_amount); + loop->remaining_amount = remaining - (max - pos); + pos = max; + break; + } + } + *amount = pos; + + return has_more; +} + +internal +Sys_CLI_End_Update_Sig(system_cli_end_update){ + b32 close_me = 0; + HANDLE proc = *(HANDLE*)&cli->proc; + DWORD result = 0; + + if (WaitForSingleObject(proc, 0) == WAIT_OBJECT_0){ + if (GetExitCodeProcess(proc, &result) == 0) + cli->exit = -1; + else + cli->exit = (i32)result; + + close_me = 1; + CloseHandle(*(HANDLE*)&cli->proc); + CloseHandle(*(HANDLE*)&cli->out_read); + CloseHandle(*(HANDLE*)&cli->out_write); + } + return close_me; +} + +internal void +fnt__remove(Win32_Font_Load_Parameters *params){ + params->next->prev = params->prev; + params->prev->next = params->next; +} + +internal void +fnt__insert(Win32_Font_Load_Parameters *pos, Win32_Font_Load_Parameters *params){ + params->next = pos->next; + pos->next->prev = params; + pos->next = params; + params->prev = pos; +} + +internal +Font_Load_Sig(system_draw_font_load){ + Win32_Font_Load_Parameters *params; + + system_acquire_lock(FONT_LOCK); + params = win32vars.free_font_param.next; + fnt__remove(params); + fnt__insert(&win32vars.used_font_param, params); + system_release_lock(FONT_LOCK); + + params->font_out = font_out; + params->filename = filename; + params->pt_size = pt_size; + params->tab_width = tab_width; + + SendMessage(win32vars.window_handle, + WM_4coder_LOAD_FONT, + 0, (i32)(params - win32vars.fnt_params)); + return(1); +} + +internal b32 +Win32LoadAppCode(){ + b32 result = 0; + +#if UseWinDll + win32vars.app_code = LoadLibraryA("4ed_app.dll"); + if (win32vars.app_code){ + result = 1; + App_Get_Functions *get_funcs = (App_Get_Functions*) + GetProcAddress(win32vars.app_code, "app_get_functions"); + + win32vars.app = get_funcs(); + } + +#else + Data file = system_load_file("4ed_app.dll"); + + if (file.data){ + i32 error; + DLL_Data dll_data; + if (dll_parse_headers(file, &dll_data, &error)){ + Data img; + img.size = dll_total_loaded_size(&dll_data); + img.data = (byte*) + VirtualAlloc((LPVOID)Tbytes(3), img.size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + + dll_load(img, &win32vars.app_dll, file, &dll_data); + + DWORD extra_; + VirtualProtect(img.data + win32vars.app_dll.text_start, + win32vars.app_dll.text_size, + PAGE_EXECUTE_READ, + &extra_); + + result = 1; + App_Get_Functions *get_functions = (App_Get_Functions*) + dll_load_function(&win32vars.app_dll, "app_get_functions", 17); + } + else{ + // TODO(allen): file loading error + } + + system_free(file.data); + + DUMP((byte*)(Tbytes(3)), Kbytes(400)); + } + else{ + // TODO(allen): file loading error + } + +#endif + + return result; +} + +internal void +Win32LoadSystemCode(){ + win32vars.system->file_time_stamp = system_file_time_stamp; + win32vars.system->set_file_list = system_set_file_list; + + win32vars.system->directory_has_file = system_directory_has_file; + win32vars.system->directory_cd = system_directory_cd; + + win32vars.system->post_clipboard = system_post_clipboard; + win32vars.system->time = system_time; + + win32vars.system->cli_call = system_cli_call; + win32vars.system->cli_begin_update = system_cli_begin_update; + win32vars.system->cli_update_step = system_cli_update_step; + win32vars.system->cli_end_update = system_cli_end_update; + + win32vars.system->post_job = system_post_job; + win32vars.system->cancel_job = system_cancel_job; + win32vars.system->grow_thread_memory = system_grow_thread_memory; + win32vars.system->acquire_lock = system_acquire_lock; + win32vars.system->release_lock = system_release_lock; + + win32vars.system->internal_sentinel = INTERNAL_system_sentinel; + win32vars.system->internal_get_thread_states = INTERNAL_get_thread_states; + win32vars.system->internal_debug_message = INTERNAL_system_debug_message; +} + +void +ex__file_insert(File_Slot *pos, File_Slot *file){ + file->next = pos->next; + file->next->prev = file; + file->prev = pos; + pos->next = file; +} + +void +ex__insert_range(File_Slot *start, File_Slot *end, File_Slot *pos){ + end->next->prev = start->prev; + start->prev->next = end->next; + + end->next = pos->next; + start->prev = pos; + pos->next->prev = end; + pos->next = start; +} + +internal void +ex__check_file(File_Slot *pos){ + File_Slot *file = pos; + + Assert(pos == pos->next->prev); + + for (pos = pos->next; + file != pos; + pos = pos->next){ + Assert(pos == pos->next->prev); + } +} + +internal void +ex__check(File_Exchange *file_exchange){ + ex__check_file(&file_exchange->available); + ex__check_file(&file_exchange->active); + ex__check_file(&file_exchange->free_list); +} + +internal LRESULT +Win32Callback(HWND hwnd, UINT uMsg, + WPARAM wParam, LPARAM lParam){ + LRESULT result = {}; + switch (uMsg){ + case WM_MENUCHAR: + case WM_SYSCHAR:break; + + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: + { + switch (wParam){ + case VK_CONTROL:case VK_LCONTROL:case VK_RCONTROL: + case VK_MENU:case VK_LMENU:case VK_RMENU: + case VK_SHIFT:case VK_LSHIFT:case VK_RSHIFT: + { + Control_Keys *controls = 0; + b8 *control_keys = 0; + controls = &win32vars.input_chunk.pers.controls; + control_keys = win32vars.input_chunk.pers.control_keys; + + system_acquire_lock(INPUT_LOCK); + + b8 down = ((lParam & Bit_31)?(0):(1)); + b8 is_right = ((lParam & Bit_24)?(1):(0)); + + if (wParam != 255){ + switch (wParam){ + case VK_SHIFT: + { + control_keys[CONTROL_KEY_SHIFT] = down; + }break; + + case VK_CONTROL: + { + if (is_right) controls->r_ctrl = down; + else controls->l_ctrl = down; + }break; + + case VK_MENU: + { + if (is_right) controls->r_alt = down; + else controls->l_alt = down; + }break; + } + + b8 ctrl, alt; + ctrl = (controls->r_ctrl || (controls->l_ctrl && !controls->r_alt)); + alt = (controls->l_alt || (controls->r_alt && !controls->l_ctrl)); + + if (win32vars.lctrl_lalt_is_altgr){ + if (controls->l_alt && controls->l_ctrl){ + ctrl = 0; + alt = 0; + } + } + + control_keys[CONTROL_KEY_CONTROL] = ctrl; + control_keys[CONTROL_KEY_ALT] = alt; + } + system_release_lock(INPUT_LOCK); + }break; + + default: + b8 previous_state, current_state; + previous_state = ((lParam & Bit_30)?(1):(0)); + current_state = ((lParam & Bit_31)?(0):(1)); + + if (current_state){ + u8 key = keycode_lookup((u8)wParam); + + i32 *count = 0; + Key_Event_Data *data = 0; + b8 *control_keys = 0; + i32 control_keys_size = 0; + + system_acquire_lock(INPUT_LOCK); + if (!previous_state){ + count = &win32vars.input_chunk.trans.key_data.press_count; + data = win32vars.input_chunk.trans.key_data.press; + } + else{ + count = &win32vars.input_chunk.trans.key_data.hold_count; + data = win32vars.input_chunk.trans.key_data.hold; + } + control_keys = win32vars.input_chunk.pers.control_keys; + control_keys_size = sizeof(win32vars.input_chunk.pers.control_keys); + + if (*count < KEY_INPUT_BUFFER_SIZE){ + if (!key){ + UINT vk = (UINT)wParam; + UINT scan = (UINT)((lParam >> 16) & 0x7F); + BYTE state[256]; + WORD x; + int result; + + GetKeyboardState(state); + if (control_keys[CONTROL_KEY_CONTROL] && + !control_keys[CONTROL_KEY_ALT]) + state[VK_CONTROL] = 0; + x = 0; + result = ToAscii(vk, scan, state, &x, 0); + if (result == 1 && x < 128){ + key = (u8)x; + if (key == '\r') key = '\n'; + data[*count].character = key; + + state[VK_CAPITAL] = 0; + x = 0; + result = ToAscii(vk, scan, state, &x, 0); + if (result == 1 && x < 128){ + key = (u8)x; + if (key == '\r') key = '\n'; + data[*count].character_no_caps_lock = key; + data[*count].keycode = key; + } + } + if (result != 1 || x >= 128){ + data[*count].character = 0; + data[*count].character_no_caps_lock = 0; + data[*count].keycode = 0; + } + } + else{ + data[*count].character = 0; + data[*count].character_no_caps_lock = 0; + data[*count].keycode = key; + } + memcpy(data[*count].modifiers, control_keys, control_keys_size); + ++(*count); + } + } + system_release_lock(INPUT_LOCK); + + result = DefWindowProc(hwnd, uMsg, wParam, lParam); + } + }break; + + case WM_INPUT: + + + case WM_MOUSEMOVE: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.mouse_x = LOWORD(lParam); + win32vars.input_chunk.pers.mouse_y = HIWORD(lParam); + system_release_lock(INPUT_LOCK); + }break; + + case WM_MOUSEWHEEL: + { + system_acquire_lock(INPUT_LOCK); + i16 rotation = GET_WHEEL_DELTA_WPARAM(wParam); + if (rotation > 0){ + win32vars.input_chunk.trans.mouse_wheel = 1; + } + else{ + win32vars.input_chunk.trans.mouse_wheel = -1; + } + system_release_lock(INPUT_LOCK); + }break; + + case WM_LBUTTONDOWN: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_l_press = 1; + win32vars.input_chunk.pers.mouse_l = 1; + system_release_lock(INPUT_LOCK); + }break; + + case WM_RBUTTONDOWN: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_r_press = 1; + win32vars.input_chunk.pers.mouse_r = 1; + system_release_lock(INPUT_LOCK); + }break; + + case WM_LBUTTONUP: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_l_release = 1; + win32vars.input_chunk.pers.mouse_l = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_RBUTTONUP: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.trans.mouse_r_release = 1; + win32vars.input_chunk.pers.mouse_r = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.mouse_l = 0; + win32vars.input_chunk.pers.mouse_r = 0; + + b8 *control_keys = win32vars.input_chunk.pers.control_keys; + for (int i = 0; i < CONTROL_KEY_COUNT; ++i) control_keys[i] = 0; + win32vars.input_chunk.pers.controls = {}; + + system_release_lock(INPUT_LOCK); + }break; + + case WM_SIZE: + { + if (win32vars.target.handle){ + i32 new_width = LOWORD(lParam); + i32 new_height = HIWORD(lParam); + + Win32Resize(new_width, new_height); + } + }break; + + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + Win32RedrawScreen(hdc); + EndPaint(hwnd, &ps); + + }break; + + case WM_4coder_PAINT: + { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + Win32RedrawScreen(hdc); + EndPaint(hwnd, &ps); + }break; + + case WM_4coder_SET_CURSOR: + { + switch (wParam){ + case APP_MOUSE_CURSOR_ARROW: + SetCursor(win32vars.cursor_arrow); break; + + case APP_MOUSE_CURSOR_IBEAM: + SetCursor(win32vars.cursor_ibeam); break; + + case APP_MOUSE_CURSOR_LEFTRIGHT: + SetCursor(win32vars.cursor_leftright); break; + + case APP_MOUSE_CURSOR_UPDOWN: + SetCursor(win32vars.cursor_updown); break; + } + }break; + + case WM_CLOSE: // NOTE(allen): I expect WM_CLOSE not WM_DESTROY + case WM_DESTROY: + { + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.keep_playing = 0; + system_release_lock(INPUT_LOCK); + }break; + + case WM_4coder_LOAD_FONT: + { + if (win32vars.fnt_part.base == 0){ + win32vars.fnt_part = Win32ScratchPartition(Mbytes(8)); + } + + Win32_Font_Load_Parameters *params = win32vars.fnt_params + lParam; + + for (b32 success = 0; success == 0;){ + + success = draw_font_load(win32vars.fnt_part.base, + win32vars.fnt_part.max, + params->font_out, + params->filename, + params->pt_size, + params->tab_width); + + if (!success){ + Win32ScratchPartitionDouble(&win32vars.fnt_part); + } + } + + system_acquire_lock(FONT_LOCK); + fnt__remove(params); + fnt__insert(&win32vars.free_font_param, params); + system_release_lock(FONT_LOCK); + }break; + + default: + { + result = DefWindowProc(hwnd, uMsg, wParam, lParam); + }break; + } + return result; +} + +DWORD +UpdateLoop(LPVOID param){ + for (;win32vars.input_chunk.pers.keep_playing;){ + i64 timer_start = system_time(); + + system_acquire_lock(INPUT_LOCK); + Win32_Input_Chunk input_chunk = win32vars.input_chunk; + win32vars.input_chunk.trans = {}; + system_release_lock(INPUT_LOCK); + + input_chunk.pers.control_keys[CONTROL_KEY_CAPS] = GetKeyState(VK_CAPITAL) & 0x1; + + POINT mouse_point; + if (GetCursorPos(&mouse_point) && ScreenToClient(win32vars.window_handle, &mouse_point)){ + if (mouse_point.x < 0 || mouse_point.x >= win32vars.target.width || + mouse_point.y < 0 || mouse_point.y >= win32vars.target.height){ + input_chunk.trans.out_of_window = 1; + } + } + else{ + input_chunk.trans.out_of_window = 1; + } + + win32vars.clipboard_contents = {}; + if (win32vars.clipboard_sequence != 0){ + DWORD new_number = GetClipboardSequenceNumber(); + if (new_number != win32vars.clipboard_sequence){ + win32vars.clipboard_sequence = new_number; + if (win32vars.next_clipboard_is_self){ + win32vars.next_clipboard_is_self = 0; + } + else if (IsClipboardFormatAvailable(CF_TEXT)){ + if (OpenClipboard(win32vars.window_handle)){ + HANDLE clip_data; + clip_data = GetClipboardData(CF_TEXT); + if (clip_data){ + win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); + if (win32vars.clipboard_contents.str){ + win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); + GlobalUnlock(clip_data); + } + } + CloseClipboard(); + } + } + } + } + + u32 redraw = exchange_vars.thread.force_redraw; + if (redraw) exchange_vars.thread.force_redraw = 0; + + Key_Input_Data input_data; + Mouse_State mouse; + Application_Step_Result result; + + input_data = input_chunk.trans.key_data; + mouse.out_of_window = input_chunk.trans.out_of_window; + + mouse.left_button = input_chunk.pers.mouse_l; + mouse.left_button_pressed = input_chunk.trans.mouse_l_press; + mouse.left_button_released = input_chunk.trans.mouse_l_release; + + mouse.right_button = input_chunk.pers.mouse_r; + mouse.right_button_pressed = input_chunk.trans.mouse_r_press; + mouse.right_button_released = input_chunk.trans.mouse_r_release; + + mouse.wheel = input_chunk.trans.mouse_wheel; + + mouse.x = input_chunk.pers.mouse_x; + mouse.y = input_chunk.pers.mouse_y; + + result.mouse_cursor_type = APP_MOUSE_CURSOR_DEFAULT; + result.redraw = redraw; + result.lctrl_lalt_is_altgr = win32vars.lctrl_lalt_is_altgr; + + win32vars.app.step(win32vars.system, + &win32vars.key_codes, + &input_data, + &mouse, + &win32vars.target, + &memory_vars, + &exchange_vars, + win32vars.clipboard_contents, + 1, win32vars.first, redraw, + &result); + + ProfileStart(OS_frame_out); + + Win32SetCursorFromUpdate(result.mouse_cursor_type); + win32vars.lctrl_lalt_is_altgr = result.lctrl_lalt_is_altgr; + + if (result.redraw) Win32RedrawFromUpdate(); + + win32vars.first = 0; + + ProfileEnd(OS_frame_out); + + ProfileStart(OS_file_process); + { + File_Slot *file; + int d = 0; + + for (file = exchange_vars.file.active.next; + file != &exchange_vars.file.active; + file = file->next){ + ++d; + + if (file->flags & FEx_Save){ + Assert((file->flags & FEx_Request) == 0); + file->flags &= (~FEx_Save); + system_save_file(file->filename, file->data, file->size); + file->flags |= FEx_Save_Complete; + } + + if (file->flags & FEx_Request){ + Assert((file->flags & FEx_Save) == 0); + file->flags &= (~FEx_Request); + Data sysfile = + system_load_file(file->filename); + if (sysfile.data == 0){ + file->flags |= FEx_Not_Exist; + } + else{ + file->flags |= FEx_Ready; + file->data = sysfile.data; + file->size = sysfile.size; + } + } + } + + Assert(d == exchange_vars.file.num_active); + + for (file = exchange_vars.file.free_list.next; + file != &exchange_vars.file.free_list; + file = file->next){ + if (file->data){ + system_free_memory(file->data); + } + } + + if (exchange_vars.file.free_list.next != &exchange_vars.file.free_list){ + ex__insert_range(exchange_vars.file.free_list.next, exchange_vars.file.free_list.prev, + &exchange_vars.file.available); + } + + ex__check(&exchange_vars.file); + } + ProfileEnd(OS_file_process); + + ProfileStart(frame_sleep); + i64 timer_end = system_time(); + i64 end_target = (timer_start + frame_useconds); + + system_release_lock(FRAME_LOCK); + while (timer_end < end_target){ + DWORD samount = (DWORD)((end_target - timer_end) / 1000); + if (samount > 0) Sleep(samount); + timer_end = system_time(); + } + system_acquire_lock(FRAME_LOCK); + timer_start = system_time(); + ProfileEnd(frame_sleep); + } + + return(0); +} + +int +WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow){ + win32vars = {}; + exchange_vars = {}; + +#if FRED_INTERNAL + win32vars.internal_bubble.next = &win32vars.internal_bubble; + win32vars.internal_bubble.prev = &win32vars.internal_bubble; + win32vars.internal_bubble.flags = MEM_BUBBLE_SYS_DEBUG; +#endif + + if (!Win32LoadAppCode()){ + // TODO(allen): Failed to load app code, serious problem. + return 99; + } + + System_Functions system_; + System_Functions *system = &system_; + win32vars.system = system; + Win32LoadSystemCode(); + + LPVOID base; +#if FRED_INTERNAL + base = (LPVOID)Tbytes(1); +#else + base = (LPVOID)0; +#endif + + memory_vars.vars_memory_size = Mbytes(2); + memory_vars.vars_memory = VirtualAlloc(base, memory_vars.vars_memory_size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + +#if FRED_INTERNAL + base = (LPVOID)Tbytes(2); +#else + base = (LPVOID)0; +#endif + memory_vars.target_memory_size = Mbytes(512); + memory_vars.target_memory = VirtualAlloc(base, memory_vars.target_memory_size, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE); + // + + if (!memory_vars.vars_memory){ + return 4; + } + + DWORD required = GetCurrentDirectory(0, 0); + required += 1; + required *= 4; + char *current_directory_mem = (char*)Win32GetMemory(required); + DWORD written = GetCurrentDirectory(required, current_directory_mem); + + String current_directory = make_string(current_directory_mem, written, required); + terminate_with_null(¤t_directory); + + Command_Line_Parameters clparams; + clparams.argv = __argv; + clparams.argc = __argc; + + i32 output_size = + win32vars.app.read_command_line(system, + &memory_vars, + current_directory, + &win32vars.settings, + clparams); + // + + if (output_size > 0){ + // TODO + } + if (output_size != 0) return 0; + + LARGE_INTEGER lpf; + QueryPerformanceFrequency(&lpf); + win32vars.performance_frequency = lpf.QuadPart; + QueryPerformanceCounter(&lpf); + win32vars.start_pcount = lpf.QuadPart; + + FILETIME filetime; + GetSystemTimeAsFileTime(&filetime); + win32vars.start_time = ((u64)filetime.dwHighDateTime << 32) | (filetime.dwLowDateTime); + win32vars.start_time /= 10; + + keycode_init(&win32vars.key_codes); + +#ifdef FRED_SUPER + char *custom_file_default = "4coder_custom.dll"; + char *custom_file; + if (win32vars.settings.custom_dll) custom_file = win32vars.settings.custom_dll; + else custom_file = custom_file_default; + + win32vars.custom = LoadLibraryA(custom_file); + if (!win32vars.custom && custom_file != custom_file_default){ + if (!win32vars.settings.custom_dll_is_strict){ + win32vars.custom = LoadLibraryA(custom_file_default); + } + } + + if (win32vars.custom){ + win32vars.custom_api.get_bindings = (Get_Binding_Data_Function*) + GetProcAddress(win32vars.custom, "get_bindings"); + } +#endif + + Thread_Context background[4]; + memset(background, 0, sizeof(background)); + win32vars.groups[BACKGROUND_THREADS].threads = background; + win32vars.groups[BACKGROUND_THREADS].count = ArrayCount(background); + + +#if UseThreadMemory + Thread_Memory thread_memory[ArrayCount(background)]; + win32vars.thread_memory = thread_memory; +#endif + + exchange_vars.thread.queues[BACKGROUND_THREADS].semaphore = + Win32GenHandle( + CreateSemaphore(0, 0, win32vars.groups[BACKGROUND_THREADS].count, 0) + ); + + u32 creation_flag = 0; + for (i32 i = 0; i < win32vars.groups[BACKGROUND_THREADS].count; ++i){ + Thread_Context *thread = win32vars.groups[BACKGROUND_THREADS].threads + i; + thread->id = i + 1; + +#if UseThreadMemory + Thread_Memory *memory = win32vars.thread_memory + i; + *memory = {}; + memory->id = thread->id; +#endif + + thread->queue = &exchange_vars.thread.queues[BACKGROUND_THREADS]; + thread->handle = CreateThread(0, 0, ThreadProc, thread, creation_flag, (LPDWORD)&thread->windows_id); + } + + Assert(win32vars.locks); + for (i32 i = 0; i < LOCK_COUNT; ++i){ + win32vars.locks[i] = CreateSemaphore(0, 1, 1, 0); + } + win32vars.DEBUG_sysmem_lock = CreateSemaphore(0, 1, 1, 0); + + win32vars.cursor_ibeam = LoadCursor(NULL, IDC_IBEAM); + win32vars.cursor_arrow = LoadCursor(NULL, IDC_ARROW); + win32vars.cursor_leftright = LoadCursor(NULL, IDC_SIZEWE); + win32vars.cursor_updown = LoadCursor(NULL, IDC_SIZENS); + win32vars.prev_mouse_cursor = APP_MOUSE_CURSOR_ARROW; + + WNDCLASS window_class = {}; + window_class.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC; + window_class.lpfnWndProc = Win32Callback; + window_class.hInstance = hInstance; + window_class.lpszClassName = "4coder-win32-wndclass"; + + if (!RegisterClass(&window_class)){ + return 1; + } + + RECT window_rect = {}; + + if (win32vars.settings.set_window_size){ + window_rect.right = win32vars.settings.window_w; + window_rect.bottom = win32vars.settings.window_h; + } + else{ + window_rect.right = 800; + window_rect.bottom = 600; + } + + if (!AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, false)){ + // TODO(allen): non-fatal diagnostics + } + +#define WINDOW_NAME "4coder-window" + + i32 window_x; + i32 window_y; + i32 window_style; + + if (win32vars.settings.set_window_pos){ + window_x = win32vars.settings.window_x; + window_y = win32vars.settings.window_y; + } + else{ + window_x = CW_USEDEFAULT; + window_y = CW_USEDEFAULT; + } + + window_style = WS_OVERLAPPEDWINDOW | WS_VISIBLE; + if (win32vars.settings.maximize_window){ + window_style |= WS_MAXIMIZE; + } + + HWND window_handle = {}; + window_handle = CreateWindowA( + window_class.lpszClassName, + WINDOW_NAME, window_style, + window_x, window_y, + window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top, + 0, 0, hInstance, 0); + + if (window_handle == 0){ + return 2; + } + + // TODO(allen): errors? + win32vars.window_handle = window_handle; + HDC hdc = GetDC(window_handle); + win32vars.window_hdc = hdc; + + GetClientRect(window_handle, &window_rect); + + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 16, + 0, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 }; + + i32 pixel_format; + pixel_format = ChoosePixelFormat(hdc, &pfd); + SetPixelFormat(hdc, pixel_format, &pfd); + + win32vars.target.handle = hdc; + win32vars.target.context = wglCreateContext(hdc); + wglMakeCurrent(hdc, (HGLRC)win32vars.target.context); + + glEnable(GL_TEXTURE_2D); + glEnable(GL_SCISSOR_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Win32Resize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); + + win32vars.clipboard_sequence = GetClipboardSequenceNumber(); + + if (win32vars.clipboard_sequence == 0){ + system_post_clipboard(make_lit_string("")); + + win32vars.clipboard_sequence = GetClipboardSequenceNumber(); + win32vars.next_clipboard_is_self = 0; + + if (win32vars.clipboard_sequence == 0){ + // TODO(allen): diagnostics + } + } + + else{ + if (IsClipboardFormatAvailable(CF_TEXT)){ + if (OpenClipboard(win32vars.window_handle)){ + HANDLE clip_data; + clip_data = GetClipboardData(CF_TEXT); + if (clip_data){ + win32vars.clipboard_contents.str = (u8*)GlobalLock(clip_data); + if (win32vars.clipboard_contents.str){ + win32vars.clipboard_contents.size = str_size((char*)win32vars.clipboard_contents.str); + GlobalUnlock(clip_data); + } + } + CloseClipboard(); + } + } + } + + win32vars.target.push_clip = draw_push_clip; + win32vars.target.pop_clip = draw_pop_clip; + win32vars.target.push_piece = draw_push_piece; + + win32vars.target.font_set.font_info_load = draw_font_info_load; + win32vars.target.font_set.font_load = system_draw_font_load; + win32vars.target.font_set.release_font = draw_release_font; + + win32vars.target.max = Mbytes(1); + win32vars.target.push_buffer = (byte*)Win32GetMemory(win32vars.target.max); + + File_Slot file_slots[32]; + exchange_vars.file.max = sizeof(file_slots) / sizeof(file_slots[0]); + exchange_vars.file.available = {}; + exchange_vars.file.available.next = &exchange_vars.file.available; + exchange_vars.file.available.prev = &exchange_vars.file.available; + + exchange_vars.file.active = {}; + exchange_vars.file.active.next = &exchange_vars.file.active; + exchange_vars.file.active.prev = &exchange_vars.file.active; + + exchange_vars.file.free_list = {}; + exchange_vars.file.free_list.next = &exchange_vars.file.free_list; + exchange_vars.file.free_list.prev = &exchange_vars.file.free_list; + + exchange_vars.file.files = file_slots; + memset(file_slots, 0, sizeof(file_slots)); + + char *filename_space = (char*) + Win32GetMemory(FileNameMax*exchange_vars.file.max); + + for (int i = 0; i < exchange_vars.file.max; ++i){ + File_Slot *slot = file_slots + i; + ex__file_insert(&exchange_vars.file.available, slot); + slot->filename = filename_space; + filename_space += FileNameMax; + } + + win32vars.free_font_param.next = &win32vars.free_font_param; + win32vars.free_font_param.prev = &win32vars.free_font_param; + + win32vars.used_font_param.next = &win32vars.used_font_param; + win32vars.used_font_param.prev = &win32vars.used_font_param; + + for (i32 i = 0; i < ArrayCount(win32vars.fnt_params); ++i){ + fnt__insert(&win32vars.free_font_param, win32vars.fnt_params + i); + } + + win32vars.app.init(win32vars.system, &win32vars.target, + &memory_vars, &exchange_vars, &win32vars.key_codes, + win32vars.clipboard_contents, current_directory, + win32vars.custom_api); + + win32vars.input_chunk.pers.keep_playing = 1; + win32vars.first = 1; + timeBeginPeriod(1); + + win32vars.update_loop_thread = + CreateThread(0, + 0, + UpdateLoop, + 0, + CREATE_SUSPENDED, + &win32vars.update_loop_thread_id); + + system_acquire_lock(FRAME_LOCK); + + ResumeThread(win32vars.update_loop_thread); + + MSG msg; + for (;win32vars.input_chunk.pers.keep_playing && GetMessage(&msg, 0, 0, 0);){ + if (msg.message == WM_QUIT){ + system_acquire_lock(INPUT_LOCK); + win32vars.input_chunk.pers.keep_playing = 0; + system_release_lock(INPUT_LOCK); + }else{ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return 0; +} + +// BOTTOM + +