Improve flags in string library
This commit is contained in:
@@ -3,6 +3,6 @@ call ../misc/compile_setup.bat
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cl -Fe:bld.exe ../build_tool/build_main.cpp -WX -W3 -wd4200 -diagnostics:column -nologo -Zi -D_CRT_SECURE_NO_WARNINGS
|
||||
cl -Fe:bld.exe ../build_tool/build_main.cpp -FC -WX -W3 -wd4200 -diagnostics:column -nologo -Zi -D_CRT_SECURE_NO_WARNINGS
|
||||
cd ..
|
||||
build\bld.exe
|
||||
|
||||
@@ -8,7 +8,7 @@ int Main() {
|
||||
Strs files = ListDir("../tests");
|
||||
CompileFiles(cc, {"../tests/main_core_as_header.cpp", "../core_library/core.c"});
|
||||
For(files) {
|
||||
if (S8_Find(it, "test_"_s, 0, 0)) {
|
||||
if (S8_Find(it, "test_"_s)) {
|
||||
CompileFiles(cc, it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,134 +43,11 @@ DEBUG = -fsanitize=address
|
||||
#define AND_CL_STRING_TERMINATE_ON_NEW_LINE
|
||||
#include "../standalone_libraries/clexer.c"
|
||||
|
||||
#define SRC_CACHE_ENTRY_COUNT 1024
|
||||
struct SRC_CacheEntry {
|
||||
uint64_t filepath_hash;
|
||||
uint64_t file_hash;
|
||||
uint64_t includes_hash;
|
||||
uint64_t total_hash;
|
||||
};
|
||||
|
||||
struct SRC_Cache {
|
||||
int entry_cap;
|
||||
int entry_len;
|
||||
SRC_CacheEntry entries[SRC_CACHE_ENTRY_COUNT];
|
||||
};
|
||||
|
||||
double SRC_Time;
|
||||
SRC_Cache *SRC_InMemoryCache;
|
||||
SRC_Cache *SRC_FromFileCache;
|
||||
CL_ArenaTuple SRC_ArenaTuple;
|
||||
S8_String SRC_CacheFilename;
|
||||
MA_Arena PernamentArena;
|
||||
MA_Arena *Perm = &PernamentArena;
|
||||
CL_SearchPaths SRC_SearchPaths = {}; // @todo;
|
||||
Table<S8_String> CMDLine;
|
||||
|
||||
void SRC_InitCache(MA_Arena *arena, S8_String cachefilename) {
|
||||
SRC_CacheFilename = cachefilename;
|
||||
CL_InitDefaultTuple(&SRC_ArenaTuple);
|
||||
|
||||
SRC_InMemoryCache = MA_PushStruct(arena, SRC_Cache);
|
||||
SRC_InMemoryCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
|
||||
|
||||
SRC_FromFileCache = MA_PushStruct(arena, SRC_Cache);
|
||||
SRC_FromFileCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
|
||||
|
||||
S8_String cache = OS_ReadFile(arena, SRC_CacheFilename);
|
||||
if (cache.len) MA_MemoryCopy(SRC_FromFileCache, cache.str, cache.len);
|
||||
}
|
||||
|
||||
void SRC_SaveCache() {
|
||||
S8_String dump = S8_Make((char *)SRC_InMemoryCache, sizeof(SRC_Cache));
|
||||
OS_WriteFile(SRC_CacheFilename, dump);
|
||||
}
|
||||
|
||||
SRC_CacheEntry *SRC_AddHash(uint64_t filepath, uint64_t file, uint64_t includes) {
|
||||
IO_Assert(SRC_InMemoryCache->entry_len + 1 < SRC_InMemoryCache->entry_cap);
|
||||
SRC_CacheEntry *result = SRC_InMemoryCache->entries + SRC_InMemoryCache->entry_len++;
|
||||
result->filepath_hash = filepath;
|
||||
result->file_hash = file;
|
||||
result->includes_hash = includes;
|
||||
result->total_hash = HashBytes(result, sizeof(uint64_t) * 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
SRC_CacheEntry *SRC_FindCache(SRC_Cache *cache, uint64_t filepath_hash) {
|
||||
for (int cache_i = 0; cache_i < cache->entry_len; cache_i += 1) {
|
||||
SRC_CacheEntry *it = cache->entries + cache_i;
|
||||
if (it->filepath_hash == filepath_hash) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SRC_CacheEntry *SRC_HashFile(S8_String file, char *parent_file) {
|
||||
char *resolved_file = CL_ResolveFilepath(Perm, &SRC_SearchPaths, file.str, parent_file, false);
|
||||
if (!resolved_file) {
|
||||
IO_Printf("Failed to resolve file: %s\n", file.str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t filepath_hash = HashBytes(resolved_file, S8_Length(resolved_file));
|
||||
SRC_CacheEntry *entry = SRC_FindCache(SRC_InMemoryCache, filepath_hash);
|
||||
if (entry) return entry;
|
||||
|
||||
CL_LexResult *first_lex = CL_LexFile(&SRC_ArenaTuple, resolved_file);
|
||||
IO_Assert(first_lex);
|
||||
uint64_t file_hash = HashBytes(first_lex->stream_begin, first_lex->stream - first_lex->stream_begin);
|
||||
uint64_t includes_hash = 13;
|
||||
|
||||
CL_LexList list = CL_MakeLexList(first_lex);
|
||||
for (CL_IncludeIter iter = CL_IterateIncludes(&list); iter.filename; CL_GetNextInclude(&iter)) {
|
||||
if (iter.is_system_include) continue;
|
||||
|
||||
S8_String file_it = S8_MakeFromChar(iter.filename);
|
||||
SRC_CacheEntry *cache = SRC_HashFile(file_it, resolved_file);
|
||||
if (!cache) {
|
||||
IO_Printf("Missing cache for: %s\n", file_it.str);
|
||||
continue;
|
||||
}
|
||||
|
||||
includes_hash = HashMix(includes_hash, cache->total_hash);
|
||||
}
|
||||
|
||||
SRC_CacheEntry *result = SRC_AddHash(filepath_hash, file_hash, includes_hash);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SRC_WasModified(S8_String file, S8_String artifact_path) {
|
||||
double time_start = OS_GetTime();
|
||||
|
||||
if (OS_FileExists(file) == false) {
|
||||
IO_Printf("FAILED File doesnt exist: %.*s\n", S8_Expand(file));
|
||||
exit(0);
|
||||
}
|
||||
if (OS_IsAbsolute(file) == false) {
|
||||
file = OS_GetAbsolutePath(Perm, file);
|
||||
}
|
||||
|
||||
S8_String without_ext = S8_ChopLastPeriod(file);
|
||||
S8_String name_only = S8_SkipToLastSlash(without_ext);
|
||||
|
||||
if (artifact_path.len == 0) artifact_path = S8_Format(Perm, "%.*s.%s", S8_Expand(name_only), IF_WINDOWS_ELSE("obj", "o"));
|
||||
bool modified = OS_FileExists(artifact_path) == false;
|
||||
|
||||
SRC_CacheEntry *in_memory = SRC_HashFile(file, 0);
|
||||
IO_Assert(in_memory);
|
||||
|
||||
if (modified == false) {
|
||||
SRC_CacheEntry *from_file = SRC_FindCache(SRC_FromFileCache, in_memory->filepath_hash);
|
||||
if (from_file == 0 || (in_memory->total_hash != from_file->total_hash)) {
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
SRC_Time = SRC_Time + (OS_GetTime() - time_start);
|
||||
|
||||
return modified;
|
||||
}
|
||||
#include "cache.c"
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
@@ -28,7 +28,7 @@ int main(int argument_count, char **arguments) {
|
||||
{
|
||||
S8_List files_current_dir = OS_ListDir(Perm, S8_Lit(".."), 0);
|
||||
for (S8_Node *it = files_current_dir.first; it; it = it->next) {
|
||||
if (S8_Find(it->string, S8_Lit("build_file.c"), S8_IGNORE_CASE, 0)) {
|
||||
if (S8_Find(it->string, S8_Lit("build_file.c"), S8_IgnoreCase)) {
|
||||
build_file = it->string;
|
||||
}
|
||||
}
|
||||
|
||||
126
build_tool/cache.c
Normal file
126
build_tool/cache.c
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
#define SRC_CACHE_ENTRY_COUNT 1024
|
||||
struct SRC_CacheEntry {
|
||||
uint64_t filepath_hash;
|
||||
uint64_t file_hash;
|
||||
uint64_t includes_hash;
|
||||
uint64_t total_hash;
|
||||
};
|
||||
|
||||
struct SRC_Cache {
|
||||
int entry_cap;
|
||||
int entry_len;
|
||||
SRC_CacheEntry entries[SRC_CACHE_ENTRY_COUNT];
|
||||
};
|
||||
|
||||
double SRC_Time;
|
||||
SRC_Cache *SRC_InMemoryCache;
|
||||
SRC_Cache *SRC_FromFileCache;
|
||||
CL_ArenaTuple SRC_ArenaTuple;
|
||||
S8_String SRC_CacheFilename;
|
||||
CL_SearchPaths SRC_SearchPaths = {}; // @todo;
|
||||
|
||||
void SRC_InitCache(MA_Arena *arena, S8_String cachefilename) {
|
||||
SRC_CacheFilename = cachefilename;
|
||||
CL_InitDefaultTuple(&SRC_ArenaTuple);
|
||||
|
||||
SRC_InMemoryCache = MA_PushStruct(arena, SRC_Cache);
|
||||
SRC_InMemoryCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
|
||||
|
||||
SRC_FromFileCache = MA_PushStruct(arena, SRC_Cache);
|
||||
SRC_FromFileCache->entry_cap = SRC_CACHE_ENTRY_COUNT;
|
||||
|
||||
S8_String cache = OS_ReadFile(arena, SRC_CacheFilename);
|
||||
if (cache.len) MA_MemoryCopy(SRC_FromFileCache, cache.str, cache.len);
|
||||
}
|
||||
|
||||
void SRC_SaveCache() {
|
||||
S8_String dump = S8_Make((char *)SRC_InMemoryCache, sizeof(SRC_Cache));
|
||||
OS_WriteFile(SRC_CacheFilename, dump);
|
||||
}
|
||||
|
||||
SRC_CacheEntry *SRC_AddHash(uint64_t filepath, uint64_t file, uint64_t includes) {
|
||||
IO_Assert(SRC_InMemoryCache->entry_len + 1 < SRC_InMemoryCache->entry_cap);
|
||||
SRC_CacheEntry *result = SRC_InMemoryCache->entries + SRC_InMemoryCache->entry_len++;
|
||||
result->filepath_hash = filepath;
|
||||
result->file_hash = file;
|
||||
result->includes_hash = includes;
|
||||
result->total_hash = HashBytes(result, sizeof(uint64_t) * 3);
|
||||
return result;
|
||||
}
|
||||
|
||||
SRC_CacheEntry *SRC_FindCache(SRC_Cache *cache, uint64_t filepath_hash) {
|
||||
for (int cache_i = 0; cache_i < cache->entry_len; cache_i += 1) {
|
||||
SRC_CacheEntry *it = cache->entries + cache_i;
|
||||
if (it->filepath_hash == filepath_hash) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SRC_CacheEntry *SRC_HashFile(S8_String file, char *parent_file) {
|
||||
char *resolved_file = CL_ResolveFilepath(Perm, &SRC_SearchPaths, file.str, parent_file, false);
|
||||
if (!resolved_file) {
|
||||
IO_Printf("Failed to resolve file: %s\n", file.str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t filepath_hash = HashBytes(resolved_file, S8_Length(resolved_file));
|
||||
SRC_CacheEntry *entry = SRC_FindCache(SRC_InMemoryCache, filepath_hash);
|
||||
if (entry) return entry;
|
||||
|
||||
CL_LexResult *first_lex = CL_LexFile(&SRC_ArenaTuple, resolved_file);
|
||||
IO_Assert(first_lex);
|
||||
uint64_t file_hash = HashBytes(first_lex->stream_begin, first_lex->stream - first_lex->stream_begin);
|
||||
uint64_t includes_hash = 13;
|
||||
|
||||
CL_LexList list = CL_MakeLexList(first_lex);
|
||||
for (CL_IncludeIter iter = CL_IterateIncludes(&list); iter.filename; CL_GetNextInclude(&iter)) {
|
||||
if (iter.is_system_include) continue;
|
||||
|
||||
S8_String file_it = S8_MakeFromChar(iter.filename);
|
||||
SRC_CacheEntry *cache = SRC_HashFile(file_it, resolved_file);
|
||||
if (!cache) {
|
||||
IO_Printf("Missing cache for: %s\n", file_it.str);
|
||||
continue;
|
||||
}
|
||||
|
||||
includes_hash = HashMix(includes_hash, cache->total_hash);
|
||||
}
|
||||
|
||||
SRC_CacheEntry *result = SRC_AddHash(filepath_hash, file_hash, includes_hash);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SRC_WasModified(S8_String file, S8_String artifact_path) {
|
||||
double time_start = OS_GetTime();
|
||||
|
||||
if (OS_FileExists(file) == false) {
|
||||
IO_Printf("FAILED File doesnt exist: %.*s\n", S8_Expand(file));
|
||||
exit(0);
|
||||
}
|
||||
if (OS_IsAbsolute(file) == false) {
|
||||
file = OS_GetAbsolutePath(Perm, file);
|
||||
}
|
||||
|
||||
S8_String without_ext = S8_ChopLastPeriod(file);
|
||||
S8_String name_only = S8_SkipToLastSlash(without_ext);
|
||||
|
||||
if (artifact_path.len == 0) artifact_path = S8_Format(Perm, "%.*s.%s", S8_Expand(name_only), IF_WINDOWS_ELSE("obj", "o"));
|
||||
bool modified = OS_FileExists(artifact_path) == false;
|
||||
|
||||
SRC_CacheEntry *in_memory = SRC_HashFile(file, 0);
|
||||
IO_Assert(in_memory);
|
||||
|
||||
if (modified == false) {
|
||||
SRC_CacheEntry *from_file = SRC_FindCache(SRC_FromFileCache, in_memory->filepath_hash);
|
||||
if (from_file == 0 || (in_memory->total_hash != from_file->total_hash)) {
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
SRC_Time = SRC_Time + (OS_GetTime() - time_start);
|
||||
|
||||
return modified;
|
||||
}
|
||||
@@ -1,5 +1,19 @@
|
||||
#include "core.h"
|
||||
/*
|
||||
@todo
|
||||
- Rewrite OS_ListDir, no weird flags and conventions, [relative, absolute, is_dir]
|
||||
- add c++ default args using macros
|
||||
- Rework string flags
|
||||
- String should use allocator instead of arena?
|
||||
- Maybe remove completely null termination from S8_String, I think it might complicate and is error prone because one can sometimes assume it's null terminated and it isn't
|
||||
- Maybe create a nice C++ binding for strings,
|
||||
- also add String Arrays and String Builder, temp allocators hook ins for nicer api
|
||||
- Iterating over unicode codepoints using For
|
||||
- Redesign clexer because the Arena Tuple is hella weird
|
||||
- Maybe remove token array stuff, do standard stream thing, then you need one arena ...
|
||||
- Add filter stuff so we can get includes / comments / normal tokens etc.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#include "../standalone_libraries/stb_sprintf.h"
|
||||
#define IO_VSNPRINTF stbsp_vsnprintf
|
||||
@@ -20,3 +34,7 @@
|
||||
#include "../standalone_libraries/hash.c"
|
||||
#include "../standalone_libraries/load_library.c"
|
||||
#include "filesystem.c"
|
||||
|
||||
// #if LANG_CPP
|
||||
// #include "string.cpp"
|
||||
// #endif
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "../standalone_libraries/load_library.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if LANG_CPP
|
||||
#include "../standalone_libraries/defer.hpp"
|
||||
#define TABLE_ASSERT IO_Assert
|
||||
#define TABLE_Allocator M_Allocator
|
||||
@@ -28,4 +28,5 @@
|
||||
#define ARRAY_SET_DEFAULT_ALLOCATOR \
|
||||
if (!allocator.p) allocator = M_GetSystemAllocator();
|
||||
#include "../standalone_libraries/array.hpp"
|
||||
// #include "string.hpp"
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#include "filesystem.h"
|
||||
|
||||
#define OS_LENGTHOF(x) ((int64_t)((sizeof(x) / sizeof((x)[0]))))
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
@@ -47,7 +43,7 @@ OS_API bool OS_IsAbsolute(S8_String path) {
|
||||
|
||||
OS_API S8_String OS_GetExePath(MA_Arena *arena) {
|
||||
wchar_t wbuffer[1024];
|
||||
DWORD wsize = GetModuleFileNameW(0, wbuffer, OS_LENGTHOF(wbuffer));
|
||||
DWORD wsize = GetModuleFileNameW(0, wbuffer, MA_LENGTHOF(wbuffer));
|
||||
IO_Assert(wsize != 0);
|
||||
|
||||
S8_String path = UTF_CreateStringFromWidechar(arena, wbuffer, wsize);
|
||||
@@ -64,7 +60,7 @@ OS_API S8_String OS_GetExeDir(MA_Arena *arena) {
|
||||
|
||||
OS_API S8_String OS_GetWorkingDir(MA_Arena *arena) {
|
||||
wchar_t wbuffer[1024];
|
||||
DWORD wsize = GetCurrentDirectoryW(OS_LENGTHOF(wbuffer), wbuffer);
|
||||
DWORD wsize = GetCurrentDirectoryW(MA_LENGTHOF(wbuffer), wbuffer);
|
||||
IO_Assert(wsize != 0);
|
||||
IO_Assert(wsize < 1022);
|
||||
wbuffer[wsize++] = '/';
|
||||
@@ -77,15 +73,15 @@ OS_API S8_String OS_GetWorkingDir(MA_Arena *arena) {
|
||||
|
||||
OS_API void OS_SetWorkingDir(S8_String path) {
|
||||
wchar_t wpath[1024];
|
||||
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
|
||||
SetCurrentDirectoryW(wpath);
|
||||
}
|
||||
|
||||
OS_API S8_String OS_GetAbsolutePath(MA_Arena *arena, S8_String relative) {
|
||||
wchar_t wpath[1024];
|
||||
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), relative.str, relative.len);
|
||||
UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), relative.str, relative.len);
|
||||
wchar_t wpath_abs[1024];
|
||||
DWORD written = GetFullPathNameW((wchar_t *)wpath, OS_LENGTHOF(wpath_abs), wpath_abs, 0);
|
||||
DWORD written = GetFullPathNameW((wchar_t *)wpath, MA_LENGTHOF(wpath_abs), wpath_abs, 0);
|
||||
if (written == 0)
|
||||
return S8_MakeEmpty();
|
||||
S8_String path = UTF_CreateStringFromWidechar(arena, wpath_abs, written);
|
||||
@@ -95,7 +91,7 @@ OS_API S8_String OS_GetAbsolutePath(MA_Arena *arena, S8_String relative) {
|
||||
|
||||
OS_API bool OS_FileExists(S8_String path) {
|
||||
wchar_t wbuff[1024];
|
||||
UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), path.str, path.len);
|
||||
DWORD attribs = GetFileAttributesW(wbuff);
|
||||
bool result = attribs == INVALID_FILE_ATTRIBUTES ? false : true;
|
||||
return result;
|
||||
@@ -103,14 +99,14 @@ OS_API bool OS_FileExists(S8_String path) {
|
||||
|
||||
OS_API bool OS_IsDir(S8_String path) {
|
||||
wchar_t wbuff[1024];
|
||||
UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), path.str, path.len);
|
||||
DWORD dwAttrib = GetFileAttributesW(wbuff);
|
||||
return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
OS_API bool OS_IsFile(S8_String path) {
|
||||
wchar_t wbuff[1024];
|
||||
UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), path.str, path.len);
|
||||
DWORD dwAttrib = GetFileAttributesW(wbuff);
|
||||
bool is_file = (dwAttrib & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
return dwAttrib != INVALID_FILE_ATTRIBUTES && is_file;
|
||||
@@ -143,8 +139,8 @@ OS_API S8_List OS_ListDir(MA_Arena *arena, S8_String path, unsigned flags) {
|
||||
for (S8_Node *it = dirs_to_read.first; it; it = it->next) {
|
||||
wchar_t wbuff[1024];
|
||||
S8_String modified_path = S8_Format(scratch.arena, "%.*s\\*", (int)it->string.len, it->string.str);
|
||||
IO_Assert(modified_path.len < OS_LENGTHOF(wbuff));
|
||||
int64_t wsize = UTF_CreateWidecharFromChar(wbuff, OS_LENGTHOF(wbuff), modified_path.str, modified_path.len);
|
||||
IO_Assert(modified_path.len < MA_LENGTHOF(wbuff));
|
||||
int64_t wsize = UTF_CreateWidecharFromChar(wbuff, MA_LENGTHOF(wbuff), modified_path.str, modified_path.len);
|
||||
IO_Assert(wsize);
|
||||
|
||||
WIN32_FIND_DATAW ffd;
|
||||
@@ -197,7 +193,7 @@ OS_API S8_List OS_ListDir(MA_Arena *arena, S8_String path, unsigned flags) {
|
||||
|
||||
OS_API OS_Result OS_MakeDir(S8_String path) {
|
||||
wchar_t wpath[1024];
|
||||
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
|
||||
BOOL success = CreateDirectoryW(wpath, NULL);
|
||||
OS_Result result = OS_SUCCESS;
|
||||
if (success == 0) {
|
||||
@@ -217,10 +213,10 @@ OS_API OS_Result OS_MakeDir(S8_String path) {
|
||||
|
||||
OS_API OS_Result OS_CopyFile(S8_String from, S8_String to, bool overwrite) {
|
||||
wchar_t wfrom[1024];
|
||||
UTF_CreateWidecharFromChar(wfrom, OS_LENGTHOF(wfrom), from.str, from.len);
|
||||
UTF_CreateWidecharFromChar(wfrom, MA_LENGTHOF(wfrom), from.str, from.len);
|
||||
|
||||
wchar_t wto[1024];
|
||||
UTF_CreateWidecharFromChar(wto, OS_LENGTHOF(wto), to.str, to.len);
|
||||
UTF_CreateWidecharFromChar(wto, MA_LENGTHOF(wto), to.str, to.len);
|
||||
|
||||
BOOL fail_if_exists = !overwrite;
|
||||
BOOL success = CopyFileW(wfrom, wto, fail_if_exists);
|
||||
@@ -233,7 +229,7 @@ OS_API OS_Result OS_CopyFile(S8_String from, S8_String to, bool overwrite) {
|
||||
|
||||
OS_API OS_Result OS_DeleteFile(S8_String path) {
|
||||
wchar_t wpath[1024];
|
||||
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
|
||||
BOOL success = DeleteFileW(wpath);
|
||||
OS_Result result = OS_SUCCESS;
|
||||
if (success == 0)
|
||||
@@ -247,7 +243,7 @@ OS_API OS_Result OS_DeleteDir(S8_String path, unsigned flags) {
|
||||
S8_List list = OS_ListDir(scratch.arena, path, OS_RECURSIVE);
|
||||
S8_Node *dirs_to_remove = 0;
|
||||
for (S8_Node *it = list.first; it; it = it->next) {
|
||||
if (!S8_EndsWith(it->string, S8_Lit("/"), S8_IGNORE_CASE)) {
|
||||
if (!S8_EndsWith(it->string, S8_Lit("/"), S8_IgnoreCase)) {
|
||||
OS_DeleteFile(it->string);
|
||||
}
|
||||
else {
|
||||
@@ -264,7 +260,7 @@ OS_API OS_Result OS_DeleteDir(S8_String path, unsigned flags) {
|
||||
}
|
||||
else {
|
||||
wchar_t wpath[1024];
|
||||
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
|
||||
BOOL success = RemoveDirectoryW(wpath);
|
||||
OS_Result result = OS_SUCCESS;
|
||||
if (success == 0)
|
||||
@@ -275,7 +271,7 @@ OS_API OS_Result OS_DeleteDir(S8_String path, unsigned flags) {
|
||||
|
||||
static OS_Result OS__WriteFile(S8_String path, S8_String data, bool append) {
|
||||
wchar_t wpath[1024];
|
||||
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
|
||||
OS_Result result = OS_FAILURE;
|
||||
|
||||
DWORD access = GENERIC_WRITE;
|
||||
@@ -316,7 +312,7 @@ OS_API S8_String OS_ReadFile(MA_Arena *arena, S8_String path) {
|
||||
MA_Checkpoint checkpoint = MA_Save(arena);
|
||||
|
||||
wchar_t wpath[1024];
|
||||
UTF_CreateWidecharFromChar(wpath, OS_LENGTHOF(wpath), path.str, path.len);
|
||||
UTF_CreateWidecharFromChar(wpath, MA_LENGTHOF(wpath), path.str, path.len);
|
||||
HANDLE handle = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle != INVALID_HANDLE_VALUE) {
|
||||
LARGE_INTEGER file_size;
|
||||
@@ -680,7 +676,7 @@ OS_API S8_List S8_SplitOnRegex(MA_Arena *arena, S8_String string, S8_String rege
|
||||
S8_String before_match = S8_Make(string.str, match.pos);
|
||||
S8_String the_match = S8_Make(string.str + match.pos, match.size);
|
||||
if (before_match.len) S8_AddNode(arena, &result, before_match);
|
||||
if (flags & S8_SPLIT_INCLUSIVE) {
|
||||
if (flags & S8_SplitFlag_SplitInclusive) {
|
||||
if (the_match.len) S8_AddNode(arena, &result, the_match);
|
||||
}
|
||||
string = S8_Skip(string, match.pos + match.size);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#pragma once
|
||||
// Quick and dirty filesystem operations
|
||||
|
||||
#ifndef OS_API
|
||||
|
||||
@@ -74,7 +74,7 @@ S8_API bool S8_AreEqual(S8_String a, S8_String b, unsigned ignore_case) {
|
||||
for (int64_t i = 0; i < a.len; i++) {
|
||||
char A = a.str[i];
|
||||
char B = b.str[i];
|
||||
if (ignore_case & S8_IGNORE_CASE) {
|
||||
if (ignore_case) {
|
||||
A = CHAR_ToLowerCase(A);
|
||||
B = CHAR_ToLowerCase(B);
|
||||
}
|
||||
@@ -169,6 +169,10 @@ S8_API S8_String S8_GetPrefix(S8_String string, int64_t len) {
|
||||
return result;
|
||||
}
|
||||
|
||||
S8_API S8_String S8_GetNameNoExtension(S8_String s) {
|
||||
return S8_SkipToLastSlash(S8_ChopLastPeriod(s));
|
||||
}
|
||||
|
||||
S8_API S8_String S8_Slice(S8_String string, int64_t first_index, int64_t one_past_last_index) {
|
||||
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
|
||||
if (first_index < 0) first_index = string.len + first_index;
|
||||
@@ -245,13 +249,14 @@ S8_API S8_String S8_ToUpperCase(S8_Allocator allocator, S8_String s) {
|
||||
return copy;
|
||||
}
|
||||
|
||||
S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *index_out) {
|
||||
S8_API bool S8_Find(S8_String string, S8_String find, S8_FindFlag flags, int64_t *index_out) {
|
||||
bool ignore_case = flags & S8_FindFlag_IgnoreCase ? true : false;
|
||||
bool result = false;
|
||||
if (flags & S8_MATCH_FIND_LAST) {
|
||||
if (flags & S8_FindFlag_MatchFindLast) {
|
||||
for (int64_t i = string.len; i != 0; i--) {
|
||||
int64_t index = i - 1;
|
||||
S8_String substring = S8_Slice(string, index, index + find.len);
|
||||
if (S8_AreEqual(substring, find, flags)) {
|
||||
if (S8_AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = index;
|
||||
result = true;
|
||||
@@ -262,7 +267,7 @@ S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *i
|
||||
else {
|
||||
for (int64_t i = 0; i < string.len; i++) {
|
||||
S8_String substring = S8_Slice(string, i, i + find.len);
|
||||
if (S8_AreEqual(substring, find, flags)) {
|
||||
if (S8_AreEqual(substring, find, ignore_case)) {
|
||||
if (index_out)
|
||||
*index_out = i;
|
||||
result = true;
|
||||
@@ -274,14 +279,15 @@ S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *i
|
||||
return result;
|
||||
}
|
||||
|
||||
S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags) {
|
||||
S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0);
|
||||
S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, S8_SplitFlag flags) {
|
||||
S8_List result = S8_MakeEmptyList();
|
||||
int64_t index = 0;
|
||||
while (S8_Find(string, find, flags, &index)) {
|
||||
|
||||
S8_FindFlag find_flag = flags & S8_SplitFlag_IgnoreCase ? S8_FindFlag_IgnoreCase : S8_FindFlag_None;
|
||||
while (S8_Find(string, find, find_flag, &index)) {
|
||||
S8_String before_match = S8_Make(string.str, index);
|
||||
S8_AddNode(allocator, &result, before_match);
|
||||
if (flags & S8_SPLIT_INCLUSIVE) {
|
||||
if (flags & S8_SplitFlag_SplitInclusive) {
|
||||
S8_String match = S8_Make(string.str + index, find.len);
|
||||
S8_AddNode(allocator, &result, match);
|
||||
}
|
||||
@@ -294,7 +300,7 @@ S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find
|
||||
S8_API S8_String S8_MergeWithSeparator(S8_Allocator allocator, S8_List list, S8_String separator) {
|
||||
if (list.node_count == 0) return S8_MakeEmpty();
|
||||
if (list.char_count == 0) return S8_MakeEmpty();
|
||||
// S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0);
|
||||
|
||||
int64_t base_size = (list.char_count + 1);
|
||||
int64_t sep_size = (list.node_count - 1) * separator.len;
|
||||
int64_t size = base_size + sep_size;
|
||||
@@ -318,11 +324,11 @@ S8_API S8_String S8_Merge(S8_Allocator allocator, S8_List list) {
|
||||
return S8_MergeWithSeparator(allocator, list, S8_Lit(""));
|
||||
}
|
||||
|
||||
S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, unsigned flags) {
|
||||
S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0);
|
||||
S8_List list = S8_Split(allocator, string, replace, flags | S8_SPLIT_INCLUSIVE);
|
||||
S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, bool ignore_case) {
|
||||
S8_SplitFlag split_flag = ignore_case ? S8_SplitFlag_IgnoreCase : S8_SplitFlag_None;
|
||||
S8_List list = S8_Split(allocator, string, replace, split_flag | S8_SplitFlag_SplitInclusive);
|
||||
for (S8_Node *it = list.first; it; it = it->next) {
|
||||
if (S8_AreEqual(it->string, replace, flags)) {
|
||||
if (S8_AreEqual(it->string, replace, ignore_case)) {
|
||||
S8_ReplaceNodeString(&list, it, with);
|
||||
}
|
||||
}
|
||||
@@ -330,11 +336,12 @@ S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_Stri
|
||||
return result;
|
||||
}
|
||||
|
||||
S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags) { // @untested
|
||||
S8_ASSERT((flags & S8_MATCH_FIND_LAST) == 0);
|
||||
S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, bool ignore_case) { // @untested
|
||||
S8_List result = S8_MakeEmptyList();
|
||||
int64_t index = 0;
|
||||
while (S8_Find(string, find, flags, &index)) {
|
||||
|
||||
S8_FindFlag find_flag = ignore_case ? S8_FindFlag_IgnoreCase : 0;
|
||||
while (S8_Find(string, find, find_flag, &index)) {
|
||||
S8_String match = S8_Make(string.str + index, find.len);
|
||||
S8_AddNode(allocator, &result, match);
|
||||
string = S8_Skip(string, index + find.len);
|
||||
@@ -344,20 +351,20 @@ S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String fi
|
||||
|
||||
S8_API S8_String S8_ChopLastSlash(S8_String s) {
|
||||
S8_String result = s;
|
||||
S8_Find(s, S8_Lit("/"), S8_MATCH_FIND_LAST, &result.len);
|
||||
S8_Find(s, S8_Lit("/"), S8_FindFlag_MatchFindLast, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
S8_API S8_String S8_ChopLastPeriod(S8_String s) {
|
||||
S8_String result = s;
|
||||
S8_Find(s, S8_Lit("."), S8_MATCH_FIND_LAST, &result.len);
|
||||
S8_Find(s, S8_Lit("."), S8_FindFlag_MatchFindLast, &result.len);
|
||||
return result;
|
||||
}
|
||||
|
||||
S8_API S8_String S8_SkipToLastSlash(S8_String s) {
|
||||
int64_t pos;
|
||||
S8_String result = s;
|
||||
if (S8_Find(s, S8_Lit("/"), S8_MATCH_FIND_LAST, &pos)) {
|
||||
if (S8_Find(s, S8_Lit("/"), S8_FindFlag_MatchFindLast, &pos)) {
|
||||
result = S8_Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
@@ -366,7 +373,7 @@ S8_API S8_String S8_SkipToLastSlash(S8_String s) {
|
||||
S8_API S8_String S8_SkipToLastPeriod(S8_String s) {
|
||||
int64_t pos;
|
||||
S8_String result = s;
|
||||
if (S8_Find(s, S8_Lit("."), S8_MATCH_FIND_LAST, &pos)) {
|
||||
if (S8_Find(s, S8_Lit("."), S8_FindFlag_MatchFindLast, &pos)) {
|
||||
result = S8_Skip(result, pos + 1);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define S8_IF_CPP(x) x
|
||||
#else
|
||||
#define S8_IF_CPP(x)
|
||||
#endif
|
||||
|
||||
#ifndef S8_Allocator
|
||||
struct MA_Arena;
|
||||
#define S8_Allocator MA_Arena *
|
||||
@@ -19,12 +25,26 @@ struct MA_Arena;
|
||||
typedef struct S8_String S8_String;
|
||||
typedef struct S8_Node S8_Node;
|
||||
typedef struct S8_List S8_List;
|
||||
S8_API int64_t S8_Length(char *string);
|
||||
|
||||
struct S8_String {
|
||||
char *str;
|
||||
int64_t len;
|
||||
};
|
||||
|
||||
// #ifdef __cplusplus
|
||||
// struct String : S8_String {
|
||||
// String() = default;
|
||||
// String(char *s) : S8_String{s, S8_Length(s)} {}
|
||||
// String(char *s, int64_t l) : S8_String{s, l} {}
|
||||
// String(const char *s) : S8_String{(char *)s, S8_Length((char *)s)} {}
|
||||
// String(const char *s, int64_t l) : S8_String{(char *)s, l} {}
|
||||
// String(S8_String s) : S8_String{s.str, s.len} {}
|
||||
|
||||
// // @todo add unicode iterator
|
||||
// };
|
||||
// #endif
|
||||
|
||||
struct S8_Node {
|
||||
S8_Node *next;
|
||||
S8_String string;
|
||||
@@ -37,11 +57,20 @@ struct S8_List {
|
||||
S8_Node *last;
|
||||
};
|
||||
|
||||
const int S8_IgnoreCase = true;
|
||||
|
||||
typedef int S8_FindFlag;
|
||||
enum {
|
||||
S8_NO_FLAGS = 0,
|
||||
S8_IGNORE_CASE = 1,
|
||||
S8_SPLIT_INCLUSIVE = 4,
|
||||
S8_MATCH_FIND_LAST = 32,
|
||||
S8_FindFlag_None = 0,
|
||||
S8_FindFlag_IgnoreCase = 1,
|
||||
S8_FindFlag_MatchFindLast = 2,
|
||||
};
|
||||
|
||||
typedef int S8_SplitFlag;
|
||||
enum {
|
||||
S8_SplitFlag_None = 0,
|
||||
S8_SplitFlag_IgnoreCase = 1,
|
||||
S8_SplitFlag_SplitInclusive = 2,
|
||||
};
|
||||
|
||||
#if defined(__has_attribute)
|
||||
@@ -80,9 +109,9 @@ S8_API bool CHAR_IsAlphabetic(char a);
|
||||
S8_API bool CHAR_IsIdent(char a);
|
||||
S8_API bool CHAR_IsDigit(char a);
|
||||
S8_API bool CHAR_IsAlphanumeric(char a);
|
||||
S8_API bool S8_AreEqual(S8_String a, S8_String b, unsigned ignore_case);
|
||||
S8_API bool S8_EndsWith(S8_String a, S8_String end, unsigned ignore_case);
|
||||
S8_API bool S8_StartsWith(S8_String a, S8_String start, unsigned ignore_case);
|
||||
S8_API bool S8_AreEqual(S8_String a, S8_String b, unsigned ignore_case S8_IF_CPP(= false));
|
||||
S8_API bool S8_EndsWith(S8_String a, S8_String end, unsigned ignore_case S8_IF_CPP(= false));
|
||||
S8_API bool S8_StartsWith(S8_String a, S8_String start, unsigned ignore_case S8_IF_CPP(= false));
|
||||
S8_API S8_String S8_Make(char *str, int64_t len);
|
||||
S8_API S8_String S8_Copy(S8_Allocator allocator, S8_String string);
|
||||
S8_API void S8_NormalizePath(S8_String s);
|
||||
@@ -95,26 +124,28 @@ S8_API S8_String S8_Trim(S8_String string);
|
||||
S8_API S8_String S8_TrimEnd(S8_String string);
|
||||
S8_API S8_String S8_ToLowerCase(S8_Allocator allocator, S8_String s);
|
||||
S8_API S8_String S8_ToUpperCase(S8_Allocator allocator, S8_String s);
|
||||
S8_API bool S8_Find(S8_String string, S8_String find, unsigned flags, int64_t *index_out);
|
||||
S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags);
|
||||
S8_API S8_String S8_MergeWithSeparator(S8_Allocator allocator, S8_List list, S8_String separator);
|
||||
S8_API S8_String S8_Merge(S8_Allocator allocator, S8_List list);
|
||||
S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, unsigned flags);
|
||||
S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, unsigned flags);
|
||||
S8_API bool S8_Find(S8_String string, S8_String find, S8_FindFlag flags S8_IF_CPP(= S8_FindFlag_None), int64_t *index_out S8_IF_CPP(= 0));
|
||||
S8_API S8_String S8_ChopLastSlash(S8_String s);
|
||||
S8_API S8_String S8_ChopLastPeriod(S8_String s);
|
||||
S8_API S8_String S8_SkipToLastSlash(S8_String s);
|
||||
S8_API S8_String S8_SkipToLastPeriod(S8_String s);
|
||||
S8_API S8_String S8_GetNameNoExt(S8_String s);
|
||||
S8_API bool S8_IsPointerInside(S8_String string, char *p);
|
||||
S8_API S8_String S8_SkipToP(S8_String string, char *p);
|
||||
S8_API S8_String S8_SkipPast(S8_String string, S8_String a);
|
||||
S8_API int64_t S8_Length(char *string);
|
||||
S8_API int64_t S8_WideLength(wchar_t *string);
|
||||
S8_API S8_String S8_MakeFromChar(char *string);
|
||||
S8_API S8_String S8_MakeEmpty(void);
|
||||
S8_API S8_List S8_MakeEmptyList(void);
|
||||
S8_API S8_String S8_FormatV(S8_Allocator allocator, const char *str, va_list args1);
|
||||
S8_API S8_String S8_Format(S8_Allocator allocator, const char *str, ...) S8__PrintfFormat(2, 3);
|
||||
|
||||
S8_API S8_List S8_Split(S8_Allocator allocator, S8_String string, S8_String find, S8_SplitFlag flags S8_IF_CPP(= S8_SplitFlag_None));
|
||||
S8_API S8_String S8_MergeWithSeparator(S8_Allocator allocator, S8_List list, S8_String separator S8_IF_CPP(= " "_s));
|
||||
S8_API S8_String S8_Merge(S8_Allocator allocator, S8_List list);
|
||||
S8_API S8_String S8_ReplaceAll(S8_Allocator allocator, S8_String string, S8_String replace, S8_String with, bool ignore_case S8_IF_CPP(= false));
|
||||
S8_API S8_List S8_FindAll(S8_Allocator allocator, S8_String string, S8_String find, bool ignore_case S8_IF_CPP(= false));
|
||||
|
||||
S8_API S8_Node *S8_CreateNode(S8_Allocator allocator, S8_String string);
|
||||
S8_API void S8_ReplaceNodeString(S8_List *list, S8_Node *node, S8_String new_string);
|
||||
S8_API void S8_AddExistingNode(S8_List *list, S8_Node *node);
|
||||
|
||||
4
tests/1test_string.cpp
Normal file
4
tests/1test_string.cpp
Normal file
@@ -0,0 +1,4 @@
|
||||
#include "../core_library/core.c"
|
||||
|
||||
int main() {
|
||||
}
|
||||
Reference in New Issue
Block a user