started switching file tracking over to an integrated subsystem

master
Allen Webster 2017-03-18 17:07:25 -04:00
parent 3edcf0a5b3
commit 2b2e90c987
7 changed files with 210 additions and 326 deletions

View File

@ -275,70 +275,6 @@ eol_in_place_convert_out(char *data, i32 size, i32 max, i32 *size_out){
////////////////////////////////////// //////////////////////////////////////
// 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);
}
//////////////////////////////////////
// //
// Implementation of the gap buffer // Implementation of the gap buffer
// //

View File

@ -1,27 +1,26 @@
/* /*
* Mr. 4th Dimention - Allen Webster
Copy Right FourTech LLC, 2016 *
All Rights Are Reserved * 20.07.2016
*
The OS agnostic file tracking API for applications * File tracking API.
that want to interact with potentially many files on *
the disk that could be changed by other applications. */
Created on: 20.07.2016
*/
// TOP // TOP
#ifndef FILE_TRACK_4TECH_H #if !defined(FILE_TRACK_4TECH_H)
#define FILE_TRACK_4TECH_H #define FILE_TRACK_4TECH_H
#ifndef FILE_TRACK_LINK #if !defined(FILE_TRACK_LINK)
#define FILE_TRACK_LINK static # define FILE_TRACK_LINK static
#endif #endif
#include <stdint.h> typedef struct{
u8 opaque[128];
} File_Track_System;
typedef i32 File_Track_Result;
enum{ enum{
FileTrack_Good, FileTrack_Good,
FileTrack_MemoryTooSmall, FileTrack_MemoryTooSmall,
@ -31,16 +30,8 @@ enum{
FileTrack_FileSystemError FileTrack_FileSystemError
}; };
typedef struct{
uint8_t opaque[128];
} File_Track_System;
typedef int32_t File_Track_Result;
FILE_TRACK_LINK File_Track_Result FILE_TRACK_LINK File_Track_Result
init_track_system(File_Track_System *system, init_track_system(File_Track_System *system, void *table_memory, i32 table_memory_size, void *listener_memory, i32 listener_memory_size);
void *table_memory, int32_t table_memory_size,
void *listener_memory, int32_t listener_memory_size);
FILE_TRACK_LINK File_Track_Result FILE_TRACK_LINK File_Track_Result
add_listener(File_Track_System *system, char *filename); 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); remove_listener(File_Track_System *system, char *filename);
FILE_TRACK_LINK File_Track_Result 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 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 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 FILE_TRACK_LINK File_Track_Result
shut_down_track_system(File_Track_System *system); shut_down_track_system(File_Track_System *system);

View File

@ -1,45 +1,33 @@
/* /*
* Mr. 4th Dimention - Allen Webster
Copy Right FourTech LLC, 2016 *
All Rights Are Reserved * 20.08.2016
*
The OS agnostic file tracking API for applications * File tracking shared.
that want to interact with potentially many files on *
the disk that could be changed by other applications. */
Created on: 27.08.2016
*/
// TOP // 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{ typedef struct{
uint32_t id[4]; u32 id[4];
} File_Index; } File_Index;
typedef uint32_t rptr32; typedef u32 rptr32;
#define to_ptr(b,p) ((void*)((char*)b + p)) #define to_ptr(b,p) ((void*)((char*)b + p))
#define to_rptr32(b,p) ((rptr32)((char*)(p) - (char*)(b))) #define to_rptr32(b,p) ((rptr32)((char*)(p) - (char*)(b)))
typedef struct { typedef struct {
File_Index hash; File_Index hash;
uint32_t opaque[4]; u32 opaque[4];
} File_Track_Entry; } File_Track_Entry;
global_const File_Track_Entry null_file_track_entry = {0};
typedef struct { typedef struct {
int32_t size; i32 size;
uint32_t tracked_count; u32 tracked_count;
uint32_t max; u32 max;
rptr32 file_table; rptr32 file_table;
} File_Track_Tables; } File_Track_Tables;
@ -50,13 +38,13 @@ typedef struct DLL_Node {
static File_Index internal File_Index
zero_file_index(){ zero_file_index(){
File_Index a = {0}; File_Index a = {0};
return(a); return(a);
} }
static int32_t internal i32
file_hash_is_zero(File_Index a){ file_hash_is_zero(File_Index a){
return ((a.id[0] == 0) && return ((a.id[0] == 0) &&
(a.id[1] == 0) && (a.id[1] == 0) &&
@ -64,7 +52,7 @@ file_hash_is_zero(File_Index a){
(a.id[3] == 0)); (a.id[3] == 0));
} }
static int32_t internal i32
file_hash_is_deleted(File_Index a){ file_hash_is_deleted(File_Index a){
return ((a.id[0] == 0xFFFFFFFF) && return ((a.id[0] == 0xFFFFFFFF) &&
(a.id[1] == 0xFFFFFFFF) && (a.id[1] == 0xFFFFFFFF) &&
@ -72,7 +60,7 @@ file_hash_is_deleted(File_Index a){
(a.id[3] == 0xFFFFFFFF)); (a.id[3] == 0xFFFFFFFF));
} }
static int32_t internal i32
file_index_eq(File_Index a, File_Index b){ file_index_eq(File_Index a, File_Index b){
return ((a.id[0] == b.id[0]) && return ((a.id[0] == b.id[0]) &&
(a.id[1] == b.id[1]) && (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])); (a.id[3] == b.id[3]));
} }
static void internal void
insert_node(DLL_Node *pos, DLL_Node *node){ insert_node(DLL_Node *pos, DLL_Node *node){
node->prev = pos; node->prev = pos;
node->next = pos->next; node->next = pos->next;
@ -88,19 +76,19 @@ insert_node(DLL_Node *pos, DLL_Node *node){
node->next->prev = node; node->next->prev = node;
} }
static void internal void
remove_node(DLL_Node *node){ remove_node(DLL_Node *node){
node->next->prev = node->prev; node->next->prev = node->prev;
node->prev->next = node->next; node->prev->next = node->next;
} }
static void internal void
init_sentinel_node(DLL_Node *node){ init_sentinel_node(DLL_Node *node){
node->next = node; node->next = node;
node->prev = node; node->prev = node;
} }
static DLL_Node* internal DLL_Node*
allocate_node(DLL_Node *sentinel){ allocate_node(DLL_Node *sentinel){
DLL_Node *result = 0; DLL_Node *result = 0;
if (sentinel->next != sentinel){ if (sentinel->next != sentinel){
@ -113,17 +101,17 @@ allocate_node(DLL_Node *sentinel){
#define FILE_ENTRY_COST (sizeof(File_Track_Entry)) #define FILE_ENTRY_COST (sizeof(File_Track_Entry))
static int32_t internal i32
tracking_system_has_space(File_Track_Tables *tables, int32_t new_count){ tracking_system_has_space(File_Track_Tables *tables, i32 new_count){
uint32_t count = tables->tracked_count; u32 count = tables->tracked_count;
uint32_t max = tables->max; u32 max = tables->max;
int32_t result = ((count + new_count)*8 < max*7); i32 result = ((count + new_count)*8 < max*7);
return(result); return(result);
} }
static int32_t internal i32
entry_is_available(File_Track_Entry *entry){ entry_is_available(File_Track_Entry *entry){
int32_t result = 0; i32 result = 0;
if (entry){ if (entry){
result = result =
file_hash_is_zero(entry->hash) || file_hash_is_zero(entry->hash) ||
@ -132,12 +120,12 @@ entry_is_available(File_Track_Entry *entry){
return (result); return (result);
} }
static File_Track_Entry* internal File_Track_Entry*
tracking_system_lookup_entry(File_Track_Tables *tables, File_Index key){ tracking_system_lookup_entry(File_Track_Tables *tables, File_Index key){
uint32_t hash = key.id[0]; u32 hash = key.id[0];
uint32_t max = tables->max; u32 max = tables->max;
uint32_t index = (hash) % max; u32 index = (hash) % max;
uint32_t start = index; u32 start = index;
File_Track_Entry *entries = (File_Track_Entry*)to_ptr(tables, tables->file_table); 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); return(result);
} }
static File_Track_Entry* internal File_Track_Entry*
get_file_entry(File_Track_Tables *tables, File_Index index){ get_file_entry(File_Track_Tables *tables, File_Index index){
File_Track_Entry *entry = 0; File_Track_Entry *entry = 0;
@ -181,11 +169,11 @@ get_file_entry(File_Track_Tables *tables, File_Index index){
return(entry); return(entry);
} }
static void internal void
internal_free_slot(File_Track_Tables *tables, File_Track_Entry *entry){ internal_free_slot(File_Track_Tables *tables, File_Track_Entry *entry){
Assert(!entry_is_available(entry)); Assert(!entry_is_available(entry));
ZeroStruct(*entry); *entry = null_file_track_entry;
entry->hash.id[0] = 0xFFFFFFFF; entry->hash.id[0] = 0xFFFFFFFF;
entry->hash.id[1] = 0xFFFFFFFF; entry->hash.id[1] = 0xFFFFFFFF;
entry->hash.id[2] = 0xFFFFFFFF; entry->hash.id[2] = 0xFFFFFFFF;
@ -194,27 +182,26 @@ internal_free_slot(File_Track_Tables *tables, File_Track_Entry *entry){
--tables->tracked_count; --tables->tracked_count;
} }
static int32_t internal i32
enough_memory_to_init_table(int32_t table_memory_size){ enough_memory_to_init_table(i32 table_memory_size){
int32_t result = (sizeof(File_Track_Tables) + FILE_ENTRY_COST*8 <= table_memory_size); i32 result = (sizeof(File_Track_Tables) + FILE_ENTRY_COST*8 <= table_memory_size);
return(result); return(result);
} }
static void internal void
init_table_memory(File_Track_Tables *tables, int32_t table_memory_size){ init_table_memory(File_Track_Tables *tables, i32 table_memory_size){
tables->size = table_memory_size; tables->size = table_memory_size;
tables->tracked_count = 0; tables->tracked_count = 0;
int32_t max_number_of_entries = i32 max_number_of_entries = (table_memory_size - sizeof(*tables)) / FILE_ENTRY_COST;
(table_memory_size - sizeof(*tables)) / FILE_ENTRY_COST;
tables->file_table = sizeof(*tables); tables->file_table = sizeof(*tables);
tables->max = max_number_of_entries; tables->max = max_number_of_entries;
} }
static File_Track_Result internal File_Track_Result
move_table_memory(File_Track_Tables *original_tables, move_table_memory(File_Track_Tables *original_tables,
void *mem, int32_t size){ void *mem, i32 size){
File_Track_Result result = FileTrack_Good; File_Track_Result result = FileTrack_Good;
if (original_tables->size < size){ if (original_tables->size < size){
@ -224,24 +211,22 @@ move_table_memory(File_Track_Tables *original_tables,
{ {
tables->size = size; tables->size = size;
int32_t likely_entry_size = FILE_ENTRY_COST; i32 likely_entry_size = FILE_ENTRY_COST;
int32_t max_number_of_entries = (size - sizeof(*tables)) / likely_entry_size; i32 max_number_of_entries = (size - sizeof(*tables)) / likely_entry_size;
tables->file_table = sizeof(*tables); tables->file_table = sizeof(*tables);
tables->max = max_number_of_entries; tables->max = max_number_of_entries;
} }
if (tables->max > original_tables->max){ 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 // NOTE(allen): Rehash the tracking table
{ {
File_Track_Entry *entries = (File_Track_Entry*) File_Track_Entry *entries = (File_Track_Entry*)
to_ptr(original_tables, original_tables->file_table); to_ptr(original_tables, original_tables->file_table);
for (uint32_t index = 0; for (u32 index = 0; index < original_max; ++index){
index < original_max;
++index){
File_Track_Entry *entry = entries + index; File_Track_Entry *entry = entries + index;
if (!entry_is_available(entry)){ if (!entry_is_available(entry)){
File_Index hash = entry->hash; File_Index hash = entry->hash;
@ -267,4 +252,5 @@ move_table_memory(File_Track_Tables *original_tables,
return(result); return(result);
} }
// BOTTOM // BOTTOM

View File

@ -1,17 +1,15 @@
/* /*
* Mr. 4th Dimention - Allen Webster
The OS agnostic file tracking API for applications *
that want to interact with potentially many files on * 20.07.2016
the disk that could be changed by other applications. *
* File tracking win32.
Created on: 20.07.2016 *
*/
*/
// TOP // TOP
#include "4tech_file_track.h" #include "4ed_file_track.h"
#include "4tech_file_track_general.c"
#include <Windows.h> #include <Windows.h>
@ -19,8 +17,9 @@ typedef struct {
OVERLAPPED overlapped; OVERLAPPED overlapped;
char result[2048]; char result[2048];
HANDLE dir; HANDLE dir;
int32_t user_count; i32 user_count;
} Win32_Directory_Listener; } Win32_Directory_Listener;
global_const OVERLAPPED null_overlapped = {0};
typedef struct { typedef struct {
DLL_Node node; DLL_Node node;
@ -44,9 +43,7 @@ typedef struct {
#define to_tables(v) ((File_Track_Tables*)(v->tables)) #define to_tables(v) ((File_Track_Tables*)(v->tables))
FILE_TRACK_LINK File_Track_Result FILE_TRACK_LINK File_Track_Result
init_track_system(File_Track_System *system, init_track_system(File_Track_System *system, void *table_memory, i32 table_memory_size, void *listener_memory, i32 listener_memory_size){
void *table_memory, int32_t table_memory_size,
void *listener_memory, int32_t listener_memory_size){
File_Track_Result result = FileTrack_MemoryTooSmall; File_Track_Result result = FileTrack_MemoryTooSmall;
Win32_File_Track_Vars *vars = to_vars(system); 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); init_sentinel_node(&vars->free_sentinel);
Win32_Directory_Listener_Node *listener = (Win32_Directory_Listener_Node*)listener_memory; Win32_Directory_Listener_Node *listener = (Win32_Directory_Listener_Node*)listener_memory;
int32_t count = listener_memory_size / sizeof(Win32_Directory_Listener_Node); i32 count = listener_memory_size / sizeof(Win32_Directory_Listener_Node);
for (int32_t i = 0; i < count; ++i, ++listener){ for (i32 i = 0; i < count; ++i, ++listener){
insert_node(&vars->free_sentinel, &listener->node); insert_node(&vars->free_sentinel, &listener->node);
} }
} }
@ -83,22 +80,19 @@ init_track_system(File_Track_System *system,
return(result); return(result);
} }
static int32_t internal i32
internal_get_parent_name(char *out, int32_t max, char *name){ internal_get_parent_name(char *out, i32 max, char *name){
int32_t len, slash_i;
char *ptr = name; char *ptr = name;
for (; *ptr != 0; ++ptr); for (; *ptr != 0; ++ptr);
len = (int32_t)(ptr - name); i32 len = (i32)(ptr - name);
// TODO(allen): make this system real // TODO(allen): make this system real
Assert(len < max); Assert(len < max);
for (slash_i = len-1; i32 slash_i = len-1;
slash_i > 0 && name[slash_i] != '\\' && name[slash_i] != '/'; for (;slash_i > 0 && name[slash_i] != '\\' && name[slash_i] != '/';--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[i] = name[i];
} }
out[slash_i] = 0; out[slash_i] = 0;
@ -106,7 +100,7 @@ internal_get_parent_name(char *out, int32_t max, char *name){
return(slash_i); return(slash_i);
} }
static File_Index internal File_Index
internal_get_file_index(BY_HANDLE_FILE_INFORMATION info){ internal_get_file_index(BY_HANDLE_FILE_INFORMATION info){
File_Index hash; File_Index hash;
hash.id[0] = info.nFileIndexLow; hash.id[0] = info.nFileIndexLow;
@ -157,7 +151,7 @@ add_listener(File_Track_System *system, char *filename){
allocate_node(&vars->free_sentinel); allocate_node(&vars->free_sentinel);
if (node){ if (node){
if (CreateIoCompletionPort(dir, vars->iocp, (ULONG_PTR)node, 1)){ 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)){ if (ReadDirectoryChangesW(dir, node->listener.result, sizeof(node->listener.result), 1, FLAGS, 0, &node->listener.overlapped, 0)){
node->listener.dir = dir; node->listener.dir = dir;
node->listener.user_count = 1; node->listener.user_count = 1;
@ -216,51 +210,42 @@ remove_listener(File_Track_System *system, char *filename){
EnterCriticalSection(&vars->table_lock); 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! if (getinfo_result){
char dir_name[1024]; File_Index dir_hash = internal_get_file_index(dir_info);
internal_get_parent_name(dir_name, sizeof(dir_name), filename); File_Track_Entry *dir_lookup = tracking_system_lookup_entry(tables, dir_hash);
Win32_File_Track_Entry *win32_dir = (Win32_File_Track_Entry*)dir_lookup;
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){ Assert(!entry_is_available(dir_lookup));
File_Index dir_hash = internal_get_file_index(dir_info); Win32_Directory_Listener_Node *node = win32_dir->listener_node;
File_Track_Entry *dir_lookup = tracking_system_lookup_entry(tables, dir_hash); --node->listener.user_count;
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;
}
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{ else{
result = FileTrack_FileSystemError; result = FileTrack_FileSystemError;
} }
CloseHandle(dir);
}
else{
result = FileTrack_FileSystemError;
} }
LeaveCriticalSection(&vars->table_lock); LeaveCriticalSection(&vars->table_lock);
@ -269,17 +254,15 @@ remove_listener(File_Track_System *system, char *filename){
} }
FILE_TRACK_LINK File_Track_Result 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; File_Track_Result result = FileTrack_Good;
Win32_File_Track_Vars *vars = to_vars(system); Win32_File_Track_Vars *vars = to_vars(system);
EnterCriticalSection(&vars->table_lock); EnterCriticalSection(&vars->table_lock);
{ File_Track_Tables *original_tables = to_tables(vars);
File_Track_Tables *original_tables = to_tables(vars); result = move_table_memory(original_tables, mem, size);
result = move_table_memory(original_tables, mem, size); if (result == FileTrack_Good){
if (result == FileTrack_Good){ vars->tables = mem;
vars->tables = mem;
}
} }
LeaveCriticalSection(&vars->table_lock); 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 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; File_Track_Result result = FileTrack_Good;
Win32_File_Track_Vars *vars = to_vars(system); 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){ if (sizeof(Win32_Directory_Listener_Node) <= size){
Win32_Directory_Listener_Node *listener = (Win32_Directory_Listener_Node*)mem; Win32_Directory_Listener_Node *listener = (Win32_Directory_Listener_Node*)mem;
int32_t count = size / sizeof(Win32_Directory_Listener_Node); i32 count = size / sizeof(Win32_Directory_Listener_Node);
for (int32_t i = 0; i < count; ++i, ++listener){ for (i32 i = 0; i < count; ++i, ++listener){
insert_node(&vars->free_sentinel, &listener->node); 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 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; File_Track_Result result = FileTrack_NoMoreEvents;
Win32_File_Track_Vars *vars = to_vars(system); Win32_File_Track_Vars *vars = to_vars(system);
static int32_t has_buffered_event = 0; local_persist i32 has_buffered_event = 0;
static DWORD offset = 0; local_persist DWORD offset = 0;
static Win32_Directory_Listener listener; local_persist Win32_Directory_Listener listener;
EnterCriticalSection(&vars->table_lock); EnterCriticalSection(&vars->table_lock);
{ OVERLAPPED *overlapped = 0;
OVERLAPPED *overlapped = 0; DWORD length = 0;
DWORD length = 0; ULONG_PTR key = 0;
ULONG_PTR key = 0;
i32 has_result = 0;
int32_t has_result = 0;
if (has_buffered_event){
if (has_buffered_event){ has_buffered_event = 0;
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; has_result = 1;
} }
else{ }
if (GetQueuedCompletionStatus(vars->iocp,
&length, if (has_result){
&key,
&overlapped, FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION*)(listener.result + offset);
0)){
Win32_Directory_Listener *listener_ptr = (Win32_Directory_Listener*)overlapped; i32 len = info->FileNameLength / 2;
i32 dir_len = GetFinalPathNameByHandle(listener.dir, 0, 0, FILE_NAME_NORMALIZED);
// 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. i32 req_size = dir_len + 1 + len;
listener = *listener_ptr; *size = req_size;
if (req_size < max){
ZeroStruct(listener_ptr->overlapped); i32 pos = 0;
ReadDirectoryChangesW(listener_ptr->dir,
listener_ptr->result, pos = GetFinalPathNameByHandle(listener.dir, buffer, max, FILE_NAME_NORMALIZED);
sizeof(listener_ptr->result), buffer[pos++] = '\\';
1,
FLAGS, for (i32 i = 0; i < len; ++i, ++pos){
0, buffer[pos] = (char)info->FileName[i];
&listener_ptr->overlapped,
0);
offset = 0;
has_result = 1;
} }
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){ if (info->NextEntryOffset != 0){
// TODO(allen): We're not ready to handle this yet.
FILE_NOTIFY_INFORMATION *info = (FILE_NOTIFY_INFORMATION*)(listener.result + offset); // For now I am breaking. In the future, if there
// are more results we should stash them and return
int32_t len = info->FileNameLength / 2; // them in future calls.
int32_t dir_len = GetFinalPathNameByHandle(listener.dir, 0, 0, offset += info->NextEntryOffset;
FILE_NAME_NORMALIZED); has_buffered_event = 1;
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;
}
} }
} }
@ -423,9 +391,9 @@ shut_down_track_system(File_Track_System *system){
File_Track_Tables *tables = to_tables(vars); File_Track_Tables *tables = to_tables(vars);
File_Track_Entry *entries = (File_Track_Entry*)to_ptr(tables, tables->file_table); 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; File_Track_Entry *entry = entries + index;
if (!entry_is_available(entry)){ if (!entry_is_available(entry)){

View File

@ -1113,9 +1113,7 @@ wrap_state_consume_token(System_Functions *system, Render_Font *font, Code_Wrap_
end = fixed_end_point; end = fixed_end_point;
} }
if (i < line_start){ i = clamp_top(i, line_start);
i = line_start;
}
if (i == line_start){ if (i == line_start){
skipping_whitespace = true; skipping_whitespace = true;

View File

@ -28,6 +28,12 @@
// Program setup // Program setup
// //
#define SUPPORT_DPI 1
#define UNICODE
#define FPS 60
#define frame_useconds (1000000 / FPS)
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "4tech_defines.h" #include "4tech_defines.h"
@ -63,21 +69,20 @@
#define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_TEXTURE_MAX_LEVEL 0x813D
#include "filetrack/4tech_file_track_win32.c" //////////////////////////////
#include "4ed_file_track.h"
#include "4ed_system_shared.h" #include "4ed_system_shared.h"
#define SUPPORT_DPI 1 #include "4ed_file_track_general.cpp"
#include "4ed_file_track_win32.cpp"
#define FPS 60
#define frame_useconds (1000000 / FPS)
#define WM_4coder_ANIMATE (WM_USER + 0)
// //
// Win32_Vars structs // Win32_Vars structs
// //
#define WM_4coder_ANIMATE (WM_USER + 0)
struct Thread_Context{ struct Thread_Context{
u32 job_id; u32 job_id;
b32 running; b32 running;