Merge branch 'master' of https://bitbucket.org/4coder/4coder
						commit
						49d1f490d1
					
				|  | @ -35,24 +35,25 @@ | |||
| 
 | ||||
| #include "4ed_rendering.h" | ||||
| #include "4ed.h" | ||||
| #include "4ed_buffer_model.h" | ||||
| 
 | ||||
| #define FCPP_FORBID_MALLOC | ||||
| #include "4cpp/4cpp_lexer.h" | ||||
| 
 | ||||
| #include "4ed_doubly_linked_list.cpp" | ||||
| 
 | ||||
| #include "4ed_font_set.cpp" | ||||
| #include "4ed_translation.cpp" | ||||
| #include "4ed_rendering_helper.cpp" | ||||
| 
 | ||||
| #include "4ed_style.h" | ||||
| #include "4ed_style.cpp" | ||||
| #include "4ed_command.cpp" | ||||
| 
 | ||||
| #include "file/4coder_buffer.cpp" | ||||
| #include "file/4coder_undo.cpp" | ||||
| #include "file/4coder_file.cpp" | ||||
| #include "file/4coder_working_set.cpp" | ||||
| #include "file/4coder_hot_directory.cpp" | ||||
| #include "4ed_buffer.cpp" | ||||
| #include "4ed_undo.cpp" | ||||
| #include "4ed_file.cpp" | ||||
| #include "4ed_working_set.cpp" | ||||
| #include "4ed_hot_directory.cpp" | ||||
| 
 | ||||
| #include "4ed_gui.h" | ||||
| #include "4ed_gui.cpp" | ||||
|  |  | |||
|  | @ -13,8 +13,8 @@ | |||
| // Buffer low level operations
 | ||||
| //
 | ||||
| 
 | ||||
| #include "../font/4coder_font_data.h" | ||||
| #include "../4coder_helper/4coder_seek_types.h" | ||||
| #include "font/4coder_font_data.h" | ||||
| #include "4coder_helper/4coder_seek_types.h" | ||||
| 
 | ||||
| typedef struct Cursor_With_Index{ | ||||
|     i32 pos; | ||||
|  | @ -186,6 +186,8 @@ buffer_batch_edit_update_cursors(Cursor_With_Index *sorted_positions, i32 count, | |||
|     return(shift_amount); | ||||
| } | ||||
| 
 | ||||
| //////////////////////////////////////
 | ||||
| 
 | ||||
| internal i32 | ||||
| eol_convert_in(char *dest, char *src, i32 size){ | ||||
|     i32 i = 0, j = 0, k = 0; | ||||
|  | @ -271,80 +273,7 @@ eol_in_place_convert_out(char *data, i32 size, i32 max, i32 *size_out){ | |||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| // TODO(allen): ditch this shit yo
 | ||||
| inline i32 | ||||
| is_whitespace(char c){ | ||||
|     i32 result; | ||||
|     result = (c == ' ' || c == '\n' || c == '\r'  || c == '\t' || c == '\f' || c == '\v'); | ||||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| inline i32 | ||||
| is_alphanumeric_true(char c){ | ||||
|     return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9'); | ||||
| } | ||||
| 
 | ||||
| inline i32 | ||||
| is_alphanumeric(char c){ | ||||
|     return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '_'); | ||||
| } | ||||
| 
 | ||||
| inline i32 | ||||
| is_upper(char c){ | ||||
|     return (c >= 'A' && c <= 'Z'); | ||||
| } | ||||
| 
 | ||||
| inline i32 | ||||
| is_lower(char c){ | ||||
|     return (c >= 'a' && c <= 'z'); | ||||
| } | ||||
| 
 | ||||
| inline char | ||||
| to_upper(char c){ | ||||
|     if (is_lower(c)){ | ||||
|         c += 'A' - 'a'; | ||||
|     } | ||||
|     return(c); | ||||
| } | ||||
| 
 | ||||
| internal i32 | ||||
| is_match(char *a, char *b, i32 len){ | ||||
|     i32 result = 1; | ||||
|     for (;len > 0; --len, ++a, ++b) | ||||
|         if (*a != *b) { result = 0; break; } | ||||
|      | ||||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| internal i32 | ||||
| is_match_insensitive(char *a, char *b, i32 len){ | ||||
|     i32 result = 1; | ||||
|     for (;len > 0; --len, ++a, ++b) | ||||
|         if (to_upper(*a) != to_upper(*b)) { result = 0; break; } | ||||
|      | ||||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| struct Buffer_Model_Step{ | ||||
|     u32 type; | ||||
|     u32 value; | ||||
|     i32 i; | ||||
|     u32 byte_length; | ||||
| }; | ||||
| 
 | ||||
| struct Buffer_Model_Behavior{ | ||||
|     b32 do_newline; | ||||
|     b32 do_codepoint_advance; | ||||
|     b32 do_number_advance; | ||||
| }; | ||||
| 
 | ||||
| enum{ | ||||
|     BufferModelUnit_None, | ||||
|     BufferModelUnit_Codepoint, | ||||
|     BufferModelUnit_Numbers, | ||||
| }; | ||||
| 
 | ||||
| #include "4coder_translation.cpp" | ||||
| //////////////////////////////////////
 | ||||
| 
 | ||||
| //
 | ||||
| // Implementation of the gap buffer
 | ||||
|  | @ -409,31 +338,30 @@ buffer_init_provide_page(Gap_Buffer_Init *init, void *page, i32 page_size){ | |||
|     buffer->max = page_size; | ||||
| } | ||||
| 
 | ||||
| internal i32 | ||||
| internal b32 | ||||
| buffer_end_init(Gap_Buffer_Init *init, void *scratch, i32 scratch_size){ | ||||
|     Gap_Buffer *buffer = init->buffer; | ||||
|     i32 osize1 = 0, size1 = 0, size2 = 0, size = init->size; | ||||
|     i32 result = 0; | ||||
|     b32 result = false; | ||||
|      | ||||
|     if (buffer->data){ | ||||
|         if (buffer->max >= init->size){ | ||||
|             size2 = size >> 1; | ||||
|             size1 = osize1 = size - size2; | ||||
|              | ||||
|             if (size1 > 0){ | ||||
|                 size1 = eol_convert_in(buffer->data, init->data, size1); | ||||
|                 if (size2 > 0){ | ||||
|                     size2 = eol_convert_in(buffer->data + size1, init->data + osize1, size2); | ||||
|                 } | ||||
|     if (buffer->data && buffer->max >= init->size){ | ||||
|         i32 size = init->size; | ||||
|         i32 size2 = size >> 1; | ||||
|         i32 osize1 = size - size2; | ||||
|         i32 size1 = osize1; | ||||
|          | ||||
|         if (size1 > 0){ | ||||
|             size1 = eol_convert_in(buffer->data, init->data, size1); | ||||
|             if (size2 > 0){ | ||||
|                 size2 = eol_convert_in(buffer->data + size1, init->data + osize1, size2); | ||||
|             } | ||||
|              | ||||
|             buffer->size1 = size1; | ||||
|             buffer->size2 = size2; | ||||
|             buffer->gap_size = buffer->max - size1 - size2; | ||||
|             memmove(buffer->data + size1 + buffer->gap_size, buffer->data + size1, size2); | ||||
|              | ||||
|             result = 1; | ||||
|         } | ||||
|          | ||||
|         buffer->size1 = size1; | ||||
|         buffer->size2 = size2; | ||||
|         buffer->gap_size = buffer->max - size1 - size2; | ||||
|         memmove(buffer->data + size1 + buffer->gap_size, buffer->data + size1, size2); | ||||
|          | ||||
|         result = true; | ||||
|     } | ||||
|      | ||||
|     return(result); | ||||
|  | @ -771,7 +699,7 @@ buffer_measure_character_starts(System_Functions *system, Render_Font *font, Gap | |||
|                  | ||||
|                 translating_fully_process_byte(system, font, &tran, ch, i, size, &emits); | ||||
|                  | ||||
|                 for (TRANSLATION_DECL_OUTPUT(J, emits)){ | ||||
|                 for (TRANSLATION_DECL_EMIT_LOOP(J, emits)){ | ||||
|                     TRANSLATION_DECL_GET_STEP(step, behavior, J, emits); | ||||
|                      | ||||
|                     if (behavior.do_newline){ | ||||
|  | @ -898,7 +826,7 @@ buffer_measure_wrap_y(Buffer_Measure_Wrap_State *S_ptr, Buffer_Measure_Wrap_Para | |||
|                     translating_fully_process_byte(params.system, params.font, &S.tran, ch, S.i, S.size, &S.emits); | ||||
|                 } | ||||
|                  | ||||
|                 for (TRANSLATION_OUTPUT(S.J, S.emits)){ | ||||
|                 for (TRANSLATION_EMIT_LOOP(S.J, S.emits)){ | ||||
|                     TRANSLATION_GET_STEP(S.step, S.behavior, S.J, S.emits); | ||||
|                      | ||||
|                     if (S.behavior.do_newline){ | ||||
|  | @ -1107,7 +1035,7 @@ buffer_remeasure_character_starts(System_Functions *system, Render_Font *font, G | |||
|                 u8 ch = (u8)stream.data[char_i]; | ||||
|                 translating_fully_process_byte(system, font, &tran, ch, char_i, size, &emits); | ||||
|                  | ||||
|                 for (TRANSLATION_DECL_OUTPUT(J, emits)){ | ||||
|                 for (TRANSLATION_DECL_EMIT_LOOP(J, emits)){ | ||||
|                     TRANSLATION_DECL_GET_STEP(step, behavior, J, emits); | ||||
|                      | ||||
|                     if (behavior.do_newline){ | ||||
|  | @ -1582,7 +1510,7 @@ buffer_cursor_seek(Buffer_Cursor_Seek_State *S_ptr, Buffer_Cursor_Seek_Params pa | |||
|                     translating_fully_process_byte(params.system, params.font, &S.tran, ch, S.i, S.size, &S.emits); | ||||
|                 } | ||||
|                  | ||||
|                 for (TRANSLATION_OUTPUT(S.J, S.emits)){ | ||||
|                 for (TRANSLATION_EMIT_LOOP(S.J, S.emits)){ | ||||
|                     TRANSLATION_GET_STEP(S.step, S.behavior, S.J, S.emits); | ||||
|                      | ||||
|                     S.prev_cursor = S.this_cursor; | ||||
|  | @ -1945,7 +1873,7 @@ buffer_render_data(Buffer_Render_State *S_ptr, Buffer_Render_Params params, f32 | |||
|                     translating_fully_process_byte(params.system, params.font, &S.tran, ch, S.i, S.size, &S.emits); | ||||
|                 } | ||||
|                  | ||||
|                 for (TRANSLATION_OUTPUT(S.J, S.emits)){ | ||||
|                 for (TRANSLATION_EMIT_LOOP(S.J, S.emits)){ | ||||
|                     TRANSLATION_GET_STEP(S.step, S.behavior, S.J, S.emits); | ||||
|                      | ||||
|                     if (!S.behavior.do_newline && S.step.i >= S.wrap_unit_end){ | ||||
|  | @ -0,0 +1,37 @@ | |||
| /*
 | ||||
|  * Mr. 4th Dimention - Allen Webster | ||||
|  * | ||||
|  * 18.03.2017 | ||||
|  * | ||||
|  * Abstract model for the describing the characters of a buffer. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // TOP
 | ||||
| 
 | ||||
| #if !defined(FRED_BUFFER_MODEL_H) | ||||
| #define FRED_BUFFER_MODEL_H | ||||
| 
 | ||||
| struct Buffer_Model_Step{ | ||||
|     u32 type; | ||||
|     u32 value; | ||||
|     i32 i; | ||||
|     u32 byte_length; | ||||
| }; | ||||
| 
 | ||||
| struct Buffer_Model_Behavior{ | ||||
|     b32 do_newline; | ||||
|     b32 do_codepoint_advance; | ||||
|     b32 do_number_advance; | ||||
| }; | ||||
| 
 | ||||
| enum{ | ||||
|     BufferModelUnit_None, | ||||
|     BufferModelUnit_Codepoint, | ||||
|     BufferModelUnit_Numbers, | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| // BOTTOM
 | ||||
| 
 | ||||
|  | @ -1,27 +1,26 @@ | |||
| /*
 | ||||
| 
 | ||||
| Copy Right FourTech LLC, 2016 | ||||
| All Rights Are Reserved | ||||
| 
 | ||||
| The OS agnostic file tracking API for applications | ||||
| that want to interact with potentially many files on | ||||
| the disk that could be changed by other applications. | ||||
| 
 | ||||
| Created on: 20.07.2016 | ||||
| 
 | ||||
| */ | ||||
|  * Mr. 4th Dimention - Allen Webster | ||||
|  * | ||||
|  * 20.07.2016 | ||||
|  * | ||||
|  * File tracking API. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // TOP
 | ||||
| 
 | ||||
| #ifndef FILE_TRACK_4TECH_H | ||||
| #if !defined(FILE_TRACK_4TECH_H) | ||||
| #define FILE_TRACK_4TECH_H | ||||
| 
 | ||||
| #ifndef FILE_TRACK_LINK | ||||
| #define FILE_TRACK_LINK static | ||||
| #if !defined(FILE_TRACK_LINK) | ||||
| # define FILE_TRACK_LINK static | ||||
| #endif | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| typedef struct{ | ||||
|     u8 opaque[128]; | ||||
| } File_Track_System; | ||||
| 
 | ||||
| typedef i32 File_Track_Result; | ||||
| enum{ | ||||
|     FileTrack_Good, | ||||
|     FileTrack_MemoryTooSmall, | ||||
|  | @ -31,16 +30,8 @@ enum{ | |||
|     FileTrack_FileSystemError | ||||
| }; | ||||
| 
 | ||||
| typedef struct{ | ||||
|     uint8_t opaque[128]; | ||||
| } File_Track_System; | ||||
| 
 | ||||
| typedef int32_t File_Track_Result; | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| init_track_system(File_Track_System *system, | ||||
|                   void *table_memory, int32_t table_memory_size, | ||||
|                   void *listener_memory, int32_t listener_memory_size); | ||||
| init_track_system(File_Track_System *system, void *table_memory, i32 table_memory_size, void *listener_memory, i32 listener_memory_size); | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| add_listener(File_Track_System *system, char *filename); | ||||
|  | @ -49,13 +40,13 @@ FILE_TRACK_LINK File_Track_Result | |||
| remove_listener(File_Track_System *system, char *filename); | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| move_track_system(File_Track_System *system, void *mem, int32_t size); | ||||
| move_track_system(File_Track_System *system, void *mem, i32 size); | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| expand_track_system_listeners(File_Track_System *system, void *mem, int32_t size); | ||||
| expand_track_system_listeners(File_Track_System *system, void *mem, i32 size); | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| get_change_event(File_Track_System *system, char *buffer, int32_t max); | ||||
| get_change_event(File_Track_System *system, u8 *buffer, i32 max); | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| shut_down_track_system(File_Track_System *system); | ||||
|  | @ -1,45 +1,33 @@ | |||
| /*
 | ||||
| 
 | ||||
| Copy Right FourTech LLC, 2016 | ||||
| All Rights Are Reserved | ||||
| 
 | ||||
| The OS agnostic file tracking API for applications | ||||
| that want to interact with potentially many files on | ||||
| the disk that could be changed by other applications. | ||||
| 
 | ||||
| Created on: 27.08.2016 | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
|  * Mr. 4th Dimention - Allen Webster | ||||
|  * | ||||
|  * 20.08.2016 | ||||
|  * | ||||
|  * File tracking shared. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // TOP
 | ||||
| 
 | ||||
| #ifndef Assert | ||||
| # define Assert(c) do { if (!(c)) { *((int*)0) = 0xA11E; } } while (0) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef ZeroStruct | ||||
| # define ZeroStruct(s) for (int32_t i = 0; i < sizeof(s); ++i) { ((char*)(&(s)))[i] = 0; } | ||||
| #endif | ||||
| 
 | ||||
| typedef struct{ | ||||
|     uint32_t id[4]; | ||||
|     u32 id[4]; | ||||
| } File_Index; | ||||
| 
 | ||||
| typedef uint32_t rptr32; | ||||
| typedef u32 rptr32; | ||||
| 
 | ||||
| #define to_ptr(b,p) ((void*)((char*)b + p)) | ||||
| #define to_rptr32(b,p) ((rptr32)((char*)(p) - (char*)(b))) | ||||
| 
 | ||||
| typedef struct { | ||||
|     File_Index hash; | ||||
|     uint32_t opaque[4]; | ||||
|     u32 opaque[4]; | ||||
| } File_Track_Entry; | ||||
| global_const File_Track_Entry null_file_track_entry = {0}; | ||||
| 
 | ||||
| typedef struct { | ||||
|     int32_t size; | ||||
|     uint32_t tracked_count; | ||||
|     uint32_t max; | ||||
|     i32 size; | ||||
|     u32 tracked_count; | ||||
|     u32 max; | ||||
|     rptr32 file_table; | ||||
| } File_Track_Tables; | ||||
| 
 | ||||
|  | @ -50,13 +38,13 @@ typedef struct DLL_Node { | |||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static File_Index | ||||
| internal File_Index | ||||
| zero_file_index(){ | ||||
|     File_Index a = {0}; | ||||
|     return(a); | ||||
| } | ||||
| 
 | ||||
| static int32_t | ||||
| internal i32 | ||||
| file_hash_is_zero(File_Index a){ | ||||
|     return ((a.id[0] == 0) && | ||||
|             (a.id[1] == 0) && | ||||
|  | @ -64,7 +52,7 @@ file_hash_is_zero(File_Index a){ | |||
|             (a.id[3] == 0)); | ||||
| } | ||||
| 
 | ||||
| static int32_t | ||||
| internal i32 | ||||
| file_hash_is_deleted(File_Index a){ | ||||
|     return ((a.id[0] == 0xFFFFFFFF) && | ||||
|             (a.id[1] == 0xFFFFFFFF) && | ||||
|  | @ -72,7 +60,7 @@ file_hash_is_deleted(File_Index a){ | |||
|             (a.id[3] == 0xFFFFFFFF)); | ||||
| } | ||||
| 
 | ||||
| static int32_t | ||||
| internal i32 | ||||
| file_index_eq(File_Index a, File_Index b){ | ||||
|     return ((a.id[0] == b.id[0]) && | ||||
|             (a.id[1] == b.id[1]) && | ||||
|  | @ -80,7 +68,7 @@ file_index_eq(File_Index a, File_Index b){ | |||
|             (a.id[3] == b.id[3])); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| internal void | ||||
| insert_node(DLL_Node *pos, DLL_Node *node){ | ||||
|     node->prev = pos; | ||||
|     node->next = pos->next; | ||||
|  | @ -88,19 +76,19 @@ insert_node(DLL_Node *pos, DLL_Node *node){ | |||
|     node->next->prev = node; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| internal void | ||||
| remove_node(DLL_Node *node){ | ||||
|     node->next->prev = node->prev; | ||||
|     node->prev->next = node->next; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| internal void | ||||
| init_sentinel_node(DLL_Node *node){ | ||||
|     node->next = node; | ||||
|     node->prev = node; | ||||
| } | ||||
| 
 | ||||
| static DLL_Node* | ||||
| internal DLL_Node* | ||||
| allocate_node(DLL_Node *sentinel){ | ||||
|     DLL_Node *result = 0; | ||||
|     if (sentinel->next != sentinel){ | ||||
|  | @ -113,17 +101,17 @@ allocate_node(DLL_Node *sentinel){ | |||
| #define FILE_ENTRY_COST (sizeof(File_Track_Entry)) | ||||
| 
 | ||||
| 
 | ||||
| static int32_t | ||||
| tracking_system_has_space(File_Track_Tables *tables, int32_t new_count){ | ||||
|     uint32_t count = tables->tracked_count; | ||||
|     uint32_t max = tables->max; | ||||
|     int32_t result = ((count + new_count)*8 < max*7); | ||||
| internal i32 | ||||
| tracking_system_has_space(File_Track_Tables *tables, i32 new_count){ | ||||
|     u32 count = tables->tracked_count; | ||||
|     u32 max = tables->max; | ||||
|     i32 result = ((count + new_count)*8 < max*7); | ||||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| static int32_t | ||||
| internal i32 | ||||
| entry_is_available(File_Track_Entry *entry){ | ||||
|     int32_t result = 0; | ||||
|     i32 result = 0; | ||||
|     if (entry){ | ||||
|         result = | ||||
|             file_hash_is_zero(entry->hash) || | ||||
|  | @ -132,12 +120,12 @@ entry_is_available(File_Track_Entry *entry){ | |||
|     return (result); | ||||
| } | ||||
| 
 | ||||
| static File_Track_Entry* | ||||
| internal File_Track_Entry* | ||||
| tracking_system_lookup_entry(File_Track_Tables *tables, File_Index key){ | ||||
|     uint32_t hash = key.id[0]; | ||||
|     uint32_t max = tables->max; | ||||
|     uint32_t index = (hash) % max; | ||||
|     uint32_t start = index; | ||||
|     u32 hash = key.id[0]; | ||||
|     u32 max = tables->max; | ||||
|     u32 index = (hash) % max; | ||||
|     u32 start = index; | ||||
|      | ||||
|     File_Track_Entry *entries = (File_Track_Entry*)to_ptr(tables, tables->file_table); | ||||
|      | ||||
|  | @ -169,7 +157,7 @@ tracking_system_lookup_entry(File_Track_Tables *tables, File_Index key){ | |||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| static File_Track_Entry* | ||||
| internal File_Track_Entry* | ||||
| get_file_entry(File_Track_Tables *tables, File_Index index){ | ||||
|     File_Track_Entry *entry = 0; | ||||
|      | ||||
|  | @ -181,11 +169,11 @@ get_file_entry(File_Track_Tables *tables, File_Index index){ | |||
|     return(entry); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| internal void | ||||
| internal_free_slot(File_Track_Tables *tables, File_Track_Entry *entry){ | ||||
|     Assert(!entry_is_available(entry)); | ||||
|      | ||||
|     ZeroStruct(*entry); | ||||
|     *entry = null_file_track_entry; | ||||
|     entry->hash.id[0] = 0xFFFFFFFF; | ||||
|     entry->hash.id[1] = 0xFFFFFFFF; | ||||
|     entry->hash.id[2] = 0xFFFFFFFF; | ||||
|  | @ -194,27 +182,26 @@ internal_free_slot(File_Track_Tables *tables, File_Track_Entry *entry){ | |||
|     --tables->tracked_count; | ||||
| } | ||||
| 
 | ||||
| static int32_t | ||||
| enough_memory_to_init_table(int32_t table_memory_size){ | ||||
|     int32_t result = (sizeof(File_Track_Tables) + FILE_ENTRY_COST*8 <= table_memory_size); | ||||
| internal i32 | ||||
| enough_memory_to_init_table(i32 table_memory_size){ | ||||
|     i32 result = (sizeof(File_Track_Tables) + FILE_ENTRY_COST*8 <= table_memory_size); | ||||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| init_table_memory(File_Track_Tables *tables, int32_t table_memory_size){ | ||||
| internal void | ||||
| init_table_memory(File_Track_Tables *tables, i32 table_memory_size){ | ||||
|     tables->size = table_memory_size; | ||||
|     tables->tracked_count = 0; | ||||
|      | ||||
|     int32_t max_number_of_entries = | ||||
|         (table_memory_size - sizeof(*tables)) / FILE_ENTRY_COST; | ||||
|     i32 max_number_of_entries = (table_memory_size - sizeof(*tables)) / FILE_ENTRY_COST; | ||||
|      | ||||
|     tables->file_table = sizeof(*tables); | ||||
|     tables->max = max_number_of_entries; | ||||
| } | ||||
| 
 | ||||
| static File_Track_Result | ||||
| internal File_Track_Result | ||||
| move_table_memory(File_Track_Tables *original_tables, | ||||
|                   void *mem, int32_t size){ | ||||
|                   void *mem, i32 size){ | ||||
|     File_Track_Result result = FileTrack_Good; | ||||
|      | ||||
|     if (original_tables->size < size){ | ||||
|  | @ -224,24 +211,22 @@ move_table_memory(File_Track_Tables *original_tables, | |||
|         { | ||||
|             tables->size = size; | ||||
|              | ||||
|             int32_t likely_entry_size = FILE_ENTRY_COST; | ||||
|             int32_t max_number_of_entries = (size - sizeof(*tables)) / likely_entry_size; | ||||
|             i32 likely_entry_size = FILE_ENTRY_COST; | ||||
|             i32 max_number_of_entries = (size - sizeof(*tables)) / likely_entry_size; | ||||
|              | ||||
|             tables->file_table = sizeof(*tables); | ||||
|             tables->max = max_number_of_entries; | ||||
|         } | ||||
|          | ||||
|         if (tables->max > original_tables->max){ | ||||
|             uint32_t original_max = original_tables->max; | ||||
|             u32 original_max = original_tables->max; | ||||
|              | ||||
|             // NOTE(allen): Rehash the tracking table
 | ||||
|             { | ||||
|                 File_Track_Entry *entries = (File_Track_Entry*) | ||||
|                     to_ptr(original_tables, original_tables->file_table); | ||||
|                  | ||||
|                 for (uint32_t index = 0; | ||||
|                      index < original_max; | ||||
|                      ++index){ | ||||
|                 for (u32 index = 0; index < original_max; ++index){ | ||||
|                     File_Track_Entry *entry = entries + index; | ||||
|                     if (!entry_is_available(entry)){ | ||||
|                         File_Index hash = entry->hash; | ||||
|  | @ -267,4 +252,5 @@ move_table_memory(File_Track_Tables *original_tables, | |||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| // BOTTOM
 | ||||
| // BOTTOM
 | ||||
| 
 | ||||
|  | @ -1,17 +1,15 @@ | |||
| /*
 | ||||
| 
 | ||||
| The OS agnostic file tracking API for applications | ||||
| that want to interact with potentially many files on | ||||
| the disk that could be changed by other applications. | ||||
| 
 | ||||
| Created on: 20.07.2016 | ||||
| 
 | ||||
| */ | ||||
|  * Mr. 4th Dimention - Allen Webster | ||||
|  * | ||||
|  * 20.07.2016 | ||||
|  * | ||||
|  * File tracking win32. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // TOP
 | ||||
| 
 | ||||
| #include "4tech_file_track.h" | ||||
| #include "4tech_file_track_general.c" | ||||
| #include "4ed_file_track.h" | ||||
| 
 | ||||
| #include <Windows.h> | ||||
| 
 | ||||
|  | @ -19,8 +17,9 @@ typedef struct { | |||
|     OVERLAPPED overlapped; | ||||
|     char result[2048]; | ||||
|     HANDLE dir; | ||||
|     int32_t user_count; | ||||
|     i32 user_count; | ||||
| } Win32_Directory_Listener; | ||||
| global_const OVERLAPPED null_overlapped = {0}; | ||||
| 
 | ||||
| typedef struct { | ||||
|     DLL_Node node; | ||||
|  | @ -44,9 +43,7 @@ typedef struct { | |||
| #define to_tables(v) ((File_Track_Tables*)(v->tables)) | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| init_track_system(File_Track_System *system, | ||||
|                   void *table_memory, int32_t table_memory_size, | ||||
|                   void *listener_memory, int32_t listener_memory_size){ | ||||
| init_track_system(File_Track_System *system, void *table_memory, i32 table_memory_size, void *listener_memory, i32 listener_memory_size){ | ||||
|     File_Track_Result result = FileTrack_MemoryTooSmall; | ||||
|     Win32_File_Track_Vars *vars = to_vars(system); | ||||
|      | ||||
|  | @ -65,8 +62,8 @@ init_track_system(File_Track_System *system, | |||
|             init_sentinel_node(&vars->free_sentinel); | ||||
|              | ||||
|             Win32_Directory_Listener_Node *listener = (Win32_Directory_Listener_Node*)listener_memory; | ||||
|             int32_t count = listener_memory_size / sizeof(Win32_Directory_Listener_Node); | ||||
|             for (int32_t i = 0; i < count; ++i, ++listener){ | ||||
|             i32 count = listener_memory_size / sizeof(Win32_Directory_Listener_Node); | ||||
|             for (i32 i = 0; i < count; ++i, ++listener){ | ||||
|                 insert_node(&vars->free_sentinel, &listener->node); | ||||
|             } | ||||
|         } | ||||
|  | @ -83,22 +80,19 @@ init_track_system(File_Track_System *system, | |||
|     return(result); | ||||
| } | ||||
| 
 | ||||
| static int32_t | ||||
| internal_get_parent_name(char *out, int32_t max, char *name){ | ||||
|     int32_t len, slash_i; | ||||
|      | ||||
| internal i32 | ||||
| internal_get_parent_name(char *out, i32 max, char *name){ | ||||
|     char *ptr = name; | ||||
|     for (; *ptr != 0; ++ptr); | ||||
|     len = (int32_t)(ptr - name); | ||||
|     i32 len = (i32)(ptr - name); | ||||
|      | ||||
|     // TODO(allen): make this system real
 | ||||
|     Assert(len < max); | ||||
|      | ||||
|     for (slash_i = len-1; | ||||
|          slash_i > 0 && name[slash_i] != '\\' && name[slash_i] != '/'; | ||||
|          --slash_i); | ||||
|     i32 slash_i = len-1; | ||||
|     for (;slash_i > 0 && name[slash_i] != '\\' && name[slash_i] != '/';--slash_i); | ||||
|      | ||||
|     for (int32_t i = 0; i < slash_i; ++i){ | ||||
|     for (i32 i = 0; i < slash_i; ++i){ | ||||
|         out[i] = name[i]; | ||||
|     } | ||||
|     out[slash_i] = 0; | ||||
|  | @ -106,7 +100,7 @@ internal_get_parent_name(char *out, int32_t max, char *name){ | |||
|     return(slash_i); | ||||
| } | ||||
| 
 | ||||
| static File_Index | ||||
| internal File_Index | ||||
| internal_get_file_index(BY_HANDLE_FILE_INFORMATION info){ | ||||
|     File_Index hash; | ||||
|     hash.id[0] = info.nFileIndexLow; | ||||
|  | @ -157,7 +151,7 @@ add_listener(File_Track_System *system, char *filename){ | |||
|                             allocate_node(&vars->free_sentinel); | ||||
|                         if (node){ | ||||
|                             if (CreateIoCompletionPort(dir, vars->iocp, (ULONG_PTR)node, 1)){ | ||||
|                                 ZeroStruct(node->listener.overlapped); | ||||
|                                 node->listener.overlapped = null_overlapped; | ||||
|                                 if (ReadDirectoryChangesW(dir, node->listener.result, sizeof(node->listener.result), 1, FLAGS, 0, &node->listener.overlapped, 0)){ | ||||
|                                     node->listener.dir = dir; | ||||
|                                     node->listener.user_count = 1; | ||||
|  | @ -216,51 +210,42 @@ remove_listener(File_Track_System *system, char *filename){ | |||
|      | ||||
|     EnterCriticalSection(&vars->table_lock); | ||||
|      | ||||
|     { | ||||
|         File_Track_Tables *tables = to_tables(vars); | ||||
|     File_Track_Tables *tables = to_tables(vars); | ||||
|      | ||||
|     // TODO(allen): make this real!
 | ||||
|     char dir_name[1024]; | ||||
|     internal_get_parent_name(dir_name, sizeof(dir_name), filename); | ||||
|      | ||||
|     HANDLE dir = CreateFile(dir_name, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, 0); | ||||
|      | ||||
|     if (dir != INVALID_HANDLE_VALUE){ | ||||
|         BY_HANDLE_FILE_INFORMATION dir_info = {0}; | ||||
|         DWORD getinfo_result = GetFileInformationByHandle(dir, &dir_info); | ||||
|          | ||||
|         // TODO(allen): make this real!
 | ||||
|         char dir_name[1024]; | ||||
|         internal_get_parent_name(dir_name, sizeof(dir_name), filename); | ||||
|          | ||||
|         HANDLE dir = CreateFile( | ||||
|             dir_name, | ||||
|             FILE_LIST_DIRECTORY, | ||||
|             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | ||||
|             0, | ||||
|             OPEN_EXISTING, | ||||
|             FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, | ||||
|             0); | ||||
|          | ||||
|         if (dir != INVALID_HANDLE_VALUE){ | ||||
|             BY_HANDLE_FILE_INFORMATION dir_info = {0}; | ||||
|             DWORD getinfo_result = GetFileInformationByHandle(dir, &dir_info); | ||||
|         if (getinfo_result){ | ||||
|             File_Index dir_hash =  internal_get_file_index(dir_info); | ||||
|             File_Track_Entry *dir_lookup = tracking_system_lookup_entry(tables, dir_hash); | ||||
|             Win32_File_Track_Entry *win32_dir = (Win32_File_Track_Entry*)dir_lookup; | ||||
|              | ||||
|             if (getinfo_result){ | ||||
|                 File_Index dir_hash =  internal_get_file_index(dir_info); | ||||
|                 File_Track_Entry *dir_lookup = tracking_system_lookup_entry(tables, dir_hash); | ||||
|                 Win32_File_Track_Entry *win32_dir = (Win32_File_Track_Entry*)dir_lookup; | ||||
|                  | ||||
|                 Assert(!entry_is_available(dir_lookup)); | ||||
|                 Win32_Directory_Listener_Node *node = win32_dir->listener_node; | ||||
|                 --node->listener.user_count; | ||||
|                  | ||||
|                 if (node->listener.user_count == 0){ | ||||
|                     insert_node(&vars->free_sentinel, &node->node); | ||||
|                     CancelIo(win32_dir->dir); | ||||
|                     CloseHandle(win32_dir->dir); | ||||
|                     internal_free_slot(tables, dir_lookup); | ||||
|                 } | ||||
|             } | ||||
|             else{ | ||||
|                 result = FileTrack_FileSystemError; | ||||
|             } | ||||
|             Assert(!entry_is_available(dir_lookup)); | ||||
|             Win32_Directory_Listener_Node *node = win32_dir->listener_node; | ||||
|             --node->listener.user_count; | ||||
|              | ||||
|             CloseHandle(dir); | ||||
|             if (node->listener.user_count == 0){ | ||||
|                 insert_node(&vars->free_sentinel, &node->node); | ||||
|                 CancelIo(win32_dir->dir); | ||||
|                 CloseHandle(win32_dir->dir); | ||||
|                 internal_free_slot(tables, dir_lookup); | ||||
|             } | ||||
|         } | ||||
|         else{ | ||||
|             result = FileTrack_FileSystemError; | ||||
|         } | ||||
|          | ||||
|         CloseHandle(dir); | ||||
|     } | ||||
|     else{ | ||||
|         result = FileTrack_FileSystemError; | ||||
|     } | ||||
|      | ||||
|     LeaveCriticalSection(&vars->table_lock); | ||||
|  | @ -269,17 +254,15 @@ remove_listener(File_Track_System *system, char *filename){ | |||
| } | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| move_track_system(File_Track_System *system, void *mem, int32_t size){ | ||||
| move_track_system(File_Track_System *system, void *mem, i32 size){ | ||||
|     File_Track_Result result = FileTrack_Good; | ||||
|     Win32_File_Track_Vars *vars = to_vars(system); | ||||
|      | ||||
|     EnterCriticalSection(&vars->table_lock); | ||||
|     { | ||||
|         File_Track_Tables *original_tables = to_tables(vars); | ||||
|         result = move_table_memory(original_tables, mem, size); | ||||
|         if (result == FileTrack_Good){ | ||||
|             vars->tables = mem; | ||||
|         } | ||||
|     File_Track_Tables *original_tables = to_tables(vars); | ||||
|     result = move_table_memory(original_tables, mem, size); | ||||
|     if (result == FileTrack_Good){ | ||||
|         vars->tables = mem; | ||||
|     } | ||||
|     LeaveCriticalSection(&vars->table_lock); | ||||
|      | ||||
|  | @ -287,7 +270,7 @@ move_track_system(File_Track_System *system, void *mem, int32_t size){ | |||
| } | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| expand_track_system_listeners(File_Track_System *system, void *mem, int32_t size){ | ||||
| expand_track_system_listeners(File_Track_System *system, void *mem, i32 size){ | ||||
|     File_Track_Result result = FileTrack_Good; | ||||
|     Win32_File_Track_Vars *vars = to_vars(system); | ||||
|      | ||||
|  | @ -295,8 +278,8 @@ expand_track_system_listeners(File_Track_System *system, void *mem, int32_t size | |||
|      | ||||
|     if (sizeof(Win32_Directory_Listener_Node) <= size){ | ||||
|         Win32_Directory_Listener_Node *listener = (Win32_Directory_Listener_Node*)mem; | ||||
|         int32_t count = size / sizeof(Win32_Directory_Listener_Node); | ||||
|         for (int32_t i = 0; i < count; ++i, ++listener){ | ||||
|         i32 count = size / sizeof(Win32_Directory_Listener_Node); | ||||
|         for (i32 i = 0; i < count; ++i, ++listener){ | ||||
|             insert_node(&vars->free_sentinel, &listener->node); | ||||
|         } | ||||
|     } | ||||
|  | @ -310,99 +293,84 @@ expand_track_system_listeners(File_Track_System *system, void *mem, int32_t size | |||
| } | ||||
| 
 | ||||
| FILE_TRACK_LINK File_Track_Result | ||||
| get_change_event(File_Track_System *system, char *buffer, int32_t max, int32_t *size){ | ||||
| get_change_event(File_Track_System *system, char *buffer, i32 max, i32 *size){ | ||||
|     File_Track_Result result = FileTrack_NoMoreEvents; | ||||
|     Win32_File_Track_Vars *vars = to_vars(system); | ||||
|      | ||||
|     static int32_t has_buffered_event = 0; | ||||
|     static DWORD offset = 0; | ||||
|     static Win32_Directory_Listener listener; | ||||
|     local_persist i32 has_buffered_event = 0; | ||||
|     local_persist DWORD offset = 0; | ||||
|     local_persist Win32_Directory_Listener listener; | ||||
|      | ||||
|     EnterCriticalSection(&vars->table_lock); | ||||
|      | ||||
|     { | ||||
|         OVERLAPPED *overlapped = 0; | ||||
|         DWORD length = 0; | ||||
|         ULONG_PTR key = 0; | ||||
|          | ||||
|         int32_t has_result = 0; | ||||
|          | ||||
|         if (has_buffered_event){ | ||||
|             has_buffered_event = 0; | ||||
|     OVERLAPPED *overlapped = 0; | ||||
|     DWORD length = 0; | ||||
|     ULONG_PTR key = 0; | ||||
|      | ||||
|     b32 has_result = 0; | ||||
|      | ||||
|     if (has_buffered_event){ | ||||
|         has_buffered_event = 0; | ||||
|         has_result = 1; | ||||
|     } | ||||
|     else{ | ||||
|         if (GetQueuedCompletionStatus(vars->iocp, &length, &key, &overlapped, 0)){ | ||||
|             Win32_Directory_Listener *listener_ptr = (Win32_Directory_Listener*)overlapped; | ||||
|              | ||||
|             // NOTE(allen): Get a copy of the state of this node so we can set the node
 | ||||
|             // to work listening for changes again right away.
 | ||||
|             listener = *listener_ptr; | ||||
|              | ||||
|             listener_ptr->overlapped = null_overlapped; | ||||
|             ReadDirectoryChangesW(listener_ptr->dir, listener_ptr->result, sizeof(listener_ptr->result), 1, FLAGS, 0, &listener_ptr->overlapped, 0); | ||||
|              | ||||
|             offset = 0; | ||||
|             has_result = 1; | ||||
|         } | ||||
|         else{ | ||||
|             if (GetQueuedCompletionStatus(vars->iocp, | ||||
|                                           &length, | ||||
|                                           &key, | ||||
|                                           &overlapped, | ||||
|                                           0)){ | ||||
|                 Win32_Directory_Listener *listener_ptr = (Win32_Directory_Listener*)overlapped; | ||||
|                  | ||||
|                 // NOTE(allen): Get a copy of the state of this node so we can set the node
 | ||||
|                 // to work listening for changes again right away.
 | ||||
|                 listener = *listener_ptr; | ||||
|                  | ||||
|                 ZeroStruct(listener_ptr->overlapped); | ||||
|                 ReadDirectoryChangesW(listener_ptr->dir, | ||||
|                                       listener_ptr->result, | ||||
|                                       sizeof(listener_ptr->result), | ||||
|                                       1, | ||||
|                                       FLAGS, | ||||
|                                       0, | ||||
|                                       &listener_ptr->overlapped, | ||||
|                                       0); | ||||
|                  | ||||
|                 offset = 0; | ||||
|                 has_result = 1; | ||||
|     } | ||||
|      | ||||
|     if (has_result){ | ||||
|          | ||||
|         FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION*)(listener.result + offset); | ||||
|          | ||||
|         i32 len = info->FileNameLength / 2; | ||||
|         i32 dir_len = GetFinalPathNameByHandle(listener.dir, 0, 0, FILE_NAME_NORMALIZED); | ||||
|          | ||||
|         i32 req_size = dir_len + 1 + len; | ||||
|         *size = req_size; | ||||
|         if (req_size < max){ | ||||
|             i32 pos = 0; | ||||
|              | ||||
|             pos = GetFinalPathNameByHandle(listener.dir, buffer, max, FILE_NAME_NORMALIZED); | ||||
|             buffer[pos++] = '\\'; | ||||
|              | ||||
|             for (i32 i = 0; i < len; ++i, ++pos){ | ||||
|                 buffer[pos] = (char)info->FileName[i]; | ||||
|             } | ||||
|              | ||||
|             if (buffer[0] == '\\'){ | ||||
|                 for (i32 i = 0; i+4 < pos; ++i){ | ||||
|                     buffer[i] = buffer[i+4]; | ||||
|                 } | ||||
|                 *size -= 4; | ||||
|             } | ||||
|              | ||||
|             result = FileTrack_Good; | ||||
|         } | ||||
|         else{ | ||||
|             // TODO(allen): Need some way to stash this result so that if the
 | ||||
|             // user comes back with more memory we can give them the change
 | ||||
|             // notification they missed.
 | ||||
|             result = FileTrack_MemoryTooSmall; | ||||
|         } | ||||
|          | ||||
|         if (has_result){ | ||||
|              | ||||
|             FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION*)(listener.result + offset); | ||||
|              | ||||
|             int32_t len = info->FileNameLength / 2; | ||||
|             int32_t dir_len = GetFinalPathNameByHandle(listener.dir, 0, 0, | ||||
|                                                        FILE_NAME_NORMALIZED); | ||||
|              | ||||
|             int32_t req_size = dir_len + 1 + len; | ||||
|             *size = req_size; | ||||
|             if (req_size < max){ | ||||
|                 int32_t pos = 0; | ||||
|                  | ||||
|                 pos = GetFinalPathNameByHandle(listener.dir, buffer, max, | ||||
|                                                FILE_NAME_NORMALIZED); | ||||
|                 buffer[pos++] = '\\'; | ||||
|                  | ||||
|                 for (int32_t i = 0; i < len; ++i, ++pos){ | ||||
|                     buffer[pos] = (char)info->FileName[i]; | ||||
|                 } | ||||
|                  | ||||
|                 if (buffer[0] == '\\'){ | ||||
|                     for (int32_t i = 0; i+4 < pos; ++i){ | ||||
|                         buffer[i] = buffer[i+4]; | ||||
|                     } | ||||
|                     *size -= 4; | ||||
|                 } | ||||
|                  | ||||
|                 result = FileTrack_Good; | ||||
|             } | ||||
|             else{ | ||||
|                 // TODO(allen): Need some way to stash this result so that if the
 | ||||
|                 // user comes back with more memory we can give them the change
 | ||||
|                 // notification they missed.
 | ||||
|                 result = FileTrack_MemoryTooSmall; | ||||
|             } | ||||
|              | ||||
|             if (info->NextEntryOffset != 0){ | ||||
|                 // TODO(allen): We're not ready to handle this yet.
 | ||||
|                 // For now I am breaking.  In the future, if there
 | ||||
|                 // are more results we should stash them and return
 | ||||
|                 // them in future calls.
 | ||||
|                 offset += info->NextEntryOffset; | ||||
|                 has_buffered_event = 1; | ||||
|             } | ||||
|         if (info->NextEntryOffset != 0){ | ||||
|             // TODO(allen): We're not ready to handle this yet.
 | ||||
|             // For now I am breaking.  In the future, if there
 | ||||
|             // are more results we should stash them and return
 | ||||
|             // them in future calls.
 | ||||
|             offset += info->NextEntryOffset; | ||||
|             has_buffered_event = 1; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | @ -423,9 +391,9 @@ shut_down_track_system(File_Track_System *system){ | |||
|         File_Track_Tables *tables = to_tables(vars); | ||||
|          | ||||
|         File_Track_Entry *entries = (File_Track_Entry*)to_ptr(tables, tables->file_table); | ||||
|         uint32_t max = tables->max; | ||||
|         u32 max = tables->max; | ||||
|          | ||||
|         for (uint32_t index = 0; index < max; ++index){ | ||||
|         for (u32 index = 0; index < max; ++index){ | ||||
|             File_Track_Entry *entry = entries + index; | ||||
|              | ||||
|             if (!entry_is_available(entry)){ | ||||
|  | @ -1113,9 +1113,7 @@ wrap_state_consume_token(System_Functions *system, Render_Font *font, Code_Wrap_ | |||
|         end = fixed_end_point; | ||||
|     } | ||||
|      | ||||
|     if (i < line_start){ | ||||
|         i = line_start; | ||||
|     } | ||||
|     i = clamp_top(i, line_start); | ||||
|      | ||||
|     if (i == line_start){ | ||||
|         skipping_whitespace = true; | ||||
|  | @ -1132,7 +1130,7 @@ wrap_state_consume_token(System_Functions *system, Render_Font *font, Code_Wrap_ | |||
|             u8 ch = (u8)state->stream.data[i]; | ||||
|             translating_fully_process_byte(system, font, &state->tran, ch, i, state->size, &state->emits); | ||||
|              | ||||
|             for (TRANSLATION_OUTPUT(state->J, state->emits)){ | ||||
|             for (TRANSLATION_EMIT_LOOP(state->J, state->emits)){ | ||||
|                 TRANSLATION_GET_STEP(state->step, state->behavior, state->J, state->emits); | ||||
|                  | ||||
|                 if (state->behavior.do_newline){ | ||||
|  | @ -4767,15 +4765,15 @@ step_file_view(System_Functions *system, View *view, View *active_view, Input_Su | |||
|                             u32 total_count = system->font.get_count(); | ||||
|                             u32 count = Min(total_count, 10); | ||||
|                              | ||||
|                             for (u32 font_index = 1; font_index < count; ++font_index){ | ||||
|                             for (u32 font_index = 0; font_index < count; ++font_index){ | ||||
|                                 Font_ID this_font_id = 0; | ||||
|                                 system->font.get_ids_by_index(font_index, 1, &font_id); | ||||
|                                 system->font.get_ids_by_index(font_index, 1, &this_font_id); | ||||
|                                  | ||||
|                                 char name_space[256]; | ||||
|                                 String name = make_fixed_width_string(name_space); | ||||
|                                 name.size = system->font.get_name_by_index(font_index, name.str, name.memory_size); | ||||
|                                  | ||||
|                                 id.id[0] = (u64)this_font_id; | ||||
|                                 id.id[0] = (u64)font_index + 1; | ||||
|                                 if (this_font_id != font_id){ | ||||
|                                     if (gui_do_font_button(target, id, this_font_id, name)){ | ||||
|                                         new_font_id = this_font_id; | ||||
|  |  | |||
|  | @ -1,13 +0,0 @@ | |||
| /*
 | ||||
| * Mr. 4th Dimention - Allen Webster | ||||
| * | ||||
| * 18.12.2015 | ||||
| * | ||||
| * Font set for 4coder | ||||
| * | ||||
| */ | ||||
| 
 | ||||
| // TOP
 | ||||
| 
 | ||||
| // BOTTOM
 | ||||
| 
 | ||||
|  | @ -139,10 +139,46 @@ draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_i | |||
|         x = (f32)x_; | ||||
|          | ||||
|         f32 byte_advance = font_get_byte_advance(font); | ||||
|         f32 *sub_advances = font_get_byte_sub_advances(font); | ||||
|          | ||||
|         u8 *str = (u8*)str_.str; | ||||
|         u8 *str_end = str + str_.size; | ||||
|          | ||||
|         Translation_State tran = {0}; | ||||
|         Translation_Emits emits = {0}; | ||||
|          | ||||
|         for (u32 i = 0; str < str_end; ++str, ++i){ | ||||
|             translating_fully_process_byte(system, font, &tran, *str, i, str_.size, &emits); | ||||
|              | ||||
|             for (TRANSLATION_DECL_EMIT_LOOP(j, emits)){ | ||||
|                 TRANSLATION_DECL_GET_STEP(step, behavior, j, emits); | ||||
|                  | ||||
|                 if (behavior.do_codepoint_advance){ | ||||
|                     u32 codepoint = step.value; | ||||
|                     if (color != 0){ | ||||
|                         font_draw_glyph(target, font_id, type, codepoint, x, y, color); | ||||
|                     } | ||||
|                     x += font_get_glyph_advance(system, font, codepoint); | ||||
|                 } | ||||
|                 else if (behavior.do_number_advance){ | ||||
|                     u8 n = (u8)(step.value); | ||||
|                     if (color != 0){ | ||||
|                         u8 cs[3]; | ||||
|                         cs[0] = '\\'; | ||||
|                         byte_to_ascii(n, cs+1); | ||||
|                          | ||||
|                         f32 xx = x; | ||||
|                         for (u32 j = 0; j < 3; ++j){ | ||||
|                             font_draw_glyph(target, font_id, type, cs[j], xx, y, color); | ||||
|                             xx += sub_advances[j]; | ||||
|                         } | ||||
|                     } | ||||
|                     x += byte_advance; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|          | ||||
| #if 0 | ||||
|         for (;str < str_end;){ | ||||
|             u8 *byte = str; | ||||
|             u32 codepoint = utf8_to_u32(&str, str_end); | ||||
|  | @ -188,6 +224,7 @@ draw_string_base(System_Functions *system, Render_Target *target, Font_ID font_i | |||
|                 } | ||||
|             } | ||||
|         } | ||||
| #endif | ||||
|     } | ||||
|      | ||||
|     return(x); | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ | |||
| 
 | ||||
| // TOP
 | ||||
| 
 | ||||
| #include "4ed_buffer_model.h" | ||||
| 
 | ||||
| struct Translation_State{ | ||||
|     u8 fill_buffer[4]; | ||||
|     u32 fill_start_i; | ||||
|  | @ -196,17 +198,6 @@ translating_generate_emits(Translation_State *tran, Translation_Emit_Rule emit_r | |||
|     skip_all:; | ||||
| } | ||||
| 
 | ||||
| #if 0 | ||||
| internal void | ||||
| translating_fully_process_byte(Translation_State *tran, u8 ch, u32 i, u32 size, Translation_Emits *emits_out){ | ||||
|     Translation_Byte_Description description = {0}; | ||||
|     translating_consume_byte(tran, ch, i, size, &description); | ||||
|     Translation_Emit_Rule emit_rule = {0}; | ||||
|     translating_select_emit_rule_ASCII(tran, description, &emit_rule); | ||||
|     translating_generate_emits(tran, emit_rule, ch, i, emits_out); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| internal void | ||||
| translating_fully_process_byte(System_Functions *system, Render_Font *font, Translation_State *tran, u8 ch, u32 i, u32 size, Translation_Emits *emits_out){ | ||||
|     Translation_Byte_Description description = {0}; | ||||
|  | @ -238,12 +229,12 @@ translation_step_read(Buffer_Model_Step step, Buffer_Model_Behavior *behavior_ou | |||
|     } | ||||
| } | ||||
| 
 | ||||
| #define TRANSLATION_DECL_OUTPUT(_j,_emit) u32 _j = 0; _j < (_emit).step_count; ++_j | ||||
| #define TRANSLATION_DECL_EMIT_LOOP(_j,_emit) u32 _j = 0; _j < (_emit).step_count; ++_j | ||||
| #define TRANSLATION_DECL_GET_STEP(_step,_behav,_j,_emit)                 \ | ||||
| Buffer_Model_Step _step = _emit.steps[_j]; Buffer_Model_Behavior _behav; \ | ||||
| translation_step_read(_step, &_behav) | ||||
| 
 | ||||
| #define TRANSLATION_OUTPUT(_j,_emit) _j = 0; _j < (_emit).step_count; ++_j | ||||
| #define TRANSLATION_EMIT_LOOP(_j,_emit) _j = 0; _j < (_emit).step_count; ++_j | ||||
| #define TRANSLATION_GET_STEP(_step,_behav,_j,_emit)\ | ||||
| (_step) = _emit.steps[_j]; translation_step_read((_step), &(_behav)) | ||||
| 
 | ||||
|  | @ -28,6 +28,12 @@ | |||
| // Program setup
 | ||||
| //
 | ||||
| 
 | ||||
| #define SUPPORT_DPI 1 | ||||
| #define UNICODE | ||||
| 
 | ||||
| #define FPS 60 | ||||
| #define frame_useconds (1000000 / FPS) | ||||
| 
 | ||||
| #include <assert.h> | ||||
| #include <string.h> | ||||
| #include "4tech_defines.h" | ||||
|  | @ -63,21 +69,20 @@ | |||
| 
 | ||||
| #define GL_TEXTURE_MAX_LEVEL 0x813D | ||||
| 
 | ||||
| #include "filetrack/4tech_file_track_win32.c" | ||||
| //////////////////////////////
 | ||||
| 
 | ||||
| #include "4ed_file_track.h" | ||||
| #include "4ed_system_shared.h" | ||||
| 
 | ||||
| #define SUPPORT_DPI 1 | ||||
| 
 | ||||
| #define FPS 60 | ||||
| #define frame_useconds (1000000 / FPS) | ||||
| 
 | ||||
| #define WM_4coder_ANIMATE (WM_USER + 0) | ||||
| 
 | ||||
| #include "4ed_file_track_general.cpp" | ||||
| #include "4ed_file_track_win32.cpp" | ||||
| 
 | ||||
| //
 | ||||
| // Win32_Vars structs
 | ||||
| //
 | ||||
| 
 | ||||
| #define WM_4coder_ANIMATE (WM_USER + 0) | ||||
| 
 | ||||
| struct Thread_Context{ | ||||
|     u32 job_id; | ||||
|     b32 running; | ||||
|  |  | |||
|  | @ -31,10 +31,10 @@ internal | |||
| Sys_Font_Get_IDs_By_Index_Sig(system_font_get_ids_by_index){ | ||||
|     b32 result = false; | ||||
|     u32 stop_index = first_index + index_count; | ||||
|     if (stop_index < win32_fonts.font_count){ | ||||
|     if (stop_index <= win32_fonts.font_count){ | ||||
|         result = true; | ||||
|         for (u32 i = first_index; i < stop_index; ++i){ | ||||
|             id_out[i] = i; | ||||
|             id_out[i-first_index] = i; | ||||
|         } | ||||
|     } | ||||
|     return(result); | ||||
|  | @ -46,8 +46,8 @@ Sys_Font_Get_Name_By_Index_Sig(system_font_get_name_by_index){ | |||
|     if (font_index < win32_fonts.font_count){ | ||||
|         Render_Font *font = &win32_fonts.fonts[font_index]; | ||||
|         char *name = font->name; | ||||
|         u32 name_len = font->name_len; | ||||
|         copy_partial_cs(str_out, str_out_cap, make_string(name, name_len)); | ||||
|         length = font->name_len; | ||||
|         copy_partial_cs(str_out, str_out_cap, make_string(name, length)); | ||||
|     } | ||||
|     return(length); | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Allen Webster
						Allen Webster