Compare commits

...

11 Commits

Author SHA1 Message Date
82a6293f21 added macro try_handle() 2026-01-13 18:20:01 +05:00
c4fd22542d fixed IGNORE_RESULT macro bug 2026-01-09 09:47:41 +05:00
4cfed24ec3 fixed cpp guard 2026-01-09 05:52:38 +05:00
de88e9ff16 added List_T_destroyWithElements 2025-12-21 20:22:35 +05:00
26de01c3e7 added path_getUserDir, dir_createParent 2025-12-21 20:00:10 +05:00
7dc80c2fdf insertion sort fix 2025-12-19 08:15:28 +05:00
bdbe959e23 DateTime_parse 2025-12-15 23:21:59 +05:00
94b051e852 defer simplified 2025-12-15 13:38:03 +05:00
08d45faa83 fixed some errors 2025-12-13 03:24:46 +05:00
af0931c727 changed Error_create msg argument type to str 2025-12-13 02:30:45 +05:00
0d422cd7e5 HashMapKeyValue.value -> value_ptr 2025-12-02 20:06:02 +05:00
17 changed files with 203 additions and 89 deletions

View File

@@ -19,6 +19,8 @@ C library with collections, strings, exceptions, io...
cbuild build_static_lib_dbg cbuild build_static_lib_dbg
``` ```
6. If you use tlibc as static library, add `LINKER_LIBS` from tlibc `project.config` to your project.
## Usage ## Usage
```c ```c

View File

@@ -3,13 +3,14 @@
/// USAGE insertionSort(list.data, list.len, .id) /// USAGE insertionSort(list.data, list.len, .id)
#define insertionSort_inline(arr, n, field) \ #define insertionSort_inline(arr, n, field) \
for(i32 i = 1, j; i < n; i++) { \ for(i32 i = 1, j; i < (i32)n; i++) { \
j = i; \ j = i; \
while( j > 0 && arr[j - 1]##field > arr[i]##field){\ typeof(arr[i]) t = arr[i];\
while(j > 0 && arr[j - 1]field > t##field){\
arr[j] = arr[j - 1]; \ arr[j] = arr[j - 1]; \
j--; \ j--; \
} \ } \
arr[j] = arr[i]; \ arr[j] = t; \
} \ } \
#define binarySearch_inline(arr, n, key, field, out_index) {\ #define binarySearch_inline(arr, n, key, field, out_index) {\
@@ -17,12 +18,12 @@
i32 high = n - 1; \ i32 high = n - 1; \
while (low <= high) { \ while (low <= high) { \
i32 mid = low + (high - low) / 2; \ i32 mid = low + (high - low) / 2; \
if (arr[mid]##field == key) { \ if (arr[mid]field == key) { \
out_index = mid; \ out_index = mid; \
break; \ break; \
} \ } \
/* choose left or right half */ \ /* choose left or right half */ \
if (arr[mid]##field < key) \ if (arr[mid]field < key) \
low = mid + 1; \ low = mid + 1; \
else high = mid - 1; \ else high = mid - 1; \
} \ } \

View File

@@ -43,7 +43,7 @@ typedef struct HashMapIter {
typedef struct HashMapKeyValue { typedef struct HashMapKeyValue {
str key; str key;
void* value; void* value_ptr;
} HashMapKeyValue; } HashMapKeyValue;
static inline HashMapIter HashMapIter_create(const HashMap_* table){ static inline HashMapIter HashMapIter_create(const HashMap_* table){

View File

@@ -27,16 +27,25 @@ static inline List(T) List_##T##_construct(T* data_ptr, u32 occupied_len, u32 ca
\ \
static inline List(T) List_##T##_alloc(u32 initial_capacity) { \ static inline List(T) List_##T##_alloc(u32 initial_capacity) { \
List_ l = _List_alloc(initial_capacity, sizeof(T)); \ List_ l = _List_alloc(initial_capacity, sizeof(T)); \
return *(List(T)*)(void*)&l; \ void* l_ptr = &l; \
return *(List(T)*)l_ptr; \
} \ } \
\ \
static inline List(T) List_##T##_copy(const List(T)* src) { \ static inline List(T) List_##T##_copy(const List(T)* src) { \
List_ l = _List_copy((void*)src); \ List_ l = _List_copy((void*)src); \
return *(List(T)*)(void*)&l; \ void* l_ptr = &l; \
return *(List(T)*)l_ptr; \
} \ } \
\ \
static inline void List_##T##_destroy(List(T)* self) { _List_destroy((void*)self); } \ static inline void List_##T##_destroy(List(T)* self) { _List_destroy((void*)self); } \
\ \
static inline void List_##T##_destroyWithElements(List(T)* self, void (*elem_destructor)(T*)) { \
for(u32 i = 0; i < self->len; i++){ \
elem_destructor(self->data + i);\
} \
_List_destroy((void*)self); \
} \
\
/* alloc bigger buffer if size + len_to_add won't fit in current */ \ /* alloc bigger buffer if size + len_to_add won't fit in current */ \
static inline void List_##T##_increaseCapacity(List(T)* self, u32 len_to_add){ \ static inline void List_##T##_increaseCapacity(List(T)* self, u32 len_to_add){ \
_List_increaseCapacity((void*)self, len_to_add); \ _List_increaseCapacity((void*)self, len_to_add); \

View File

@@ -17,18 +17,21 @@ void foo(){
#if defined(__GNUC__) || defined(__TINYC__) #if defined(__GNUC__) || defined(__TINYC__)
#define Deferral(MAX_DEFER_STATEMENTS) \ #define Deferral(MAX_DEFER_STATEMENTS) \
unsigned char _num_deferrals = 0; \ int _num_deferrals = 0; \
void *_defer_return_loc = 0, *_deferrals[MAX_DEFER_STATEMENTS] = {0}; ATTRIBUTE_UNUSED void *_defer_return_loc = 0;\
ATTRIBUTE_UNUSED void *_deferrals[MAX_DEFER_STATEMENTS] = {0};
# define Defer(block) _Defer(block, __LINE__) # define Defer(block) _Defer(block, __LINE__)
# define Return _Return(__LINE__) # define Return _Return(__LINE__)
#define _defer_token_cat(a, b) a ## b #ifndef CAT2
#define CAT2(a, b) a ## b
#endif
#define _Defer(block, n) do { \ #define _Defer(block, n) do { \
_deferrals[_num_deferrals++] = && _defer_token_cat(_defer_ini, n); \ _deferrals[_num_deferrals++] = && CAT2(_defer_ini, n); \
if (0) { \ if (0) { \
_defer_token_cat(_defer_ini, n): \ CAT2(_defer_ini, n): \
block; \ block; \
if (_num_deferrals) { \ if (_num_deferrals) { \
goto *_deferrals[--_num_deferrals]; \ goto *_deferrals[--_num_deferrals]; \
@@ -39,13 +42,11 @@ void foo(){
} while (0) } while (0)
#define _Return(n) \ #define _Return(n) \
if (_num_deferrals \ if (_num_deferrals) \
/* this nonsense disables warning Wunused-but-set-variable */ \
&& _defer_return_loc == _defer_return_loc ) \
{ \ { \
_defer_return_loc = && _defer_token_cat(_defer_fini_, n); \ _defer_return_loc = && CAT2(_defer_fini_, n); \
goto *_deferrals[--_num_deferrals]; \ goto *_deferrals[--_num_deferrals]; \
} else _defer_token_cat(_defer_fini_, n): \ } else CAT2(_defer_fini_, n): \
return return
#else /* !__GNUC__ && !__TINYCC__ */ #else /* !__GNUC__ && !__TINYCC__ */
@@ -59,7 +60,7 @@ void foo(){
#endif #endif
#define Deferral(MAX_DEFER_STATEMENTS) \ #define Deferral(MAX_DEFER_STATEMENTS) \
volatile unsigned char _num_deferrals = 0; \ volatile int _num_deferrals = 0; \
jmp_buf _defer_return_loc = {0}, _deferrals[MAX_DEFER_STATEMENTS] = {0}; jmp_buf _defer_return_loc = {0}, _deferrals[MAX_DEFER_STATEMENTS] = {0};
#define Defer(block) do { \ #define Defer(block) do { \

View File

@@ -26,7 +26,7 @@ typedef struct Error {
List(ErrorCallPos) call_stack; List(ErrorCallPos) call_stack;
} Error; } Error;
Error* Error_create(const char* msg, bool is_msg_on_heap, ErrorCallPos p, Error* Error_create(str msg, bool is_msg_on_heap, ErrorCallPos p,
u16 error_code_page, u32 error_code); u16 error_code_page, u32 error_code);
void Error_free(Error* e); void Error_free(Error* e);
void Error_addCallPos(Error* e, ErrorCallPos p); void Error_addCallPos(Error* e, ErrorCallPos p);
@@ -73,8 +73,11 @@ typedef struct Result_ {
/// Warning can be suppressed by IGNORE_RESULT /// Warning can be suppressed by IGNORE_RESULT
#define Result(T) Result_ ATTRIBUTE_WARN_UNUSED_RESULT #define Result(T) Result_ ATTRIBUTE_WARN_UNUSED_RESULT
#define ResultVar(T) Result_ #define ResultVar(T) Result_
// for some stupid reason gcc requires more than 3 levels of macros to concat token with line number
#define _ignore_var_name(N) CAT2(__ignored_, N)
///USAGE: IGNORE_RESULT trySomething(); ///USAGE: IGNORE_RESULT trySomething();
#define IGNORE_RESULT Result_ __ignored_##__LINE__ ATTRIBUTE_UNUSED = #define IGNORE_RESULT Result_ _ignore_var_name(__LINE__) ATTRIBUTE_UNUSED =
#define RESULT_ERROR_CODE(CODE_PAGE, CODE, MSG, IS_MSG_ON_HEAP) (Result_){ \ #define RESULT_ERROR_CODE(CODE_PAGE, CODE, MSG, IS_MSG_ON_HEAP) (Result_){ \
@@ -83,74 +86,82 @@ typedef struct Result_ {
.u = 0 \ .u = 0 \
} }
#define RESULT_ERROR_CODE_FMT(CODE_PAGE, CODE, FORMAT, ARGS...) \ #define RESULT_ERROR_CODE_FMT(CODE_PAGE, CODE, FORMAT, ARGS...) \
RESULT_ERROR_CODE(CODE_PAGE, CODE, sprintf_malloc(FORMAT ,##ARGS), true) RESULT_ERROR_CODE(CODE_PAGE, CODE, str_from_cstr(sprintf_malloc(FORMAT ,##ARGS)), true)
#define RESULT_ERROR(MSG, IS_MSG_ON_HEAP) \ #define RESULT_ERROR(MSG, IS_MSG_ON_HEAP) \
RESULT_ERROR_CODE(NONE, 0, MSG, IS_MSG_ON_HEAP); RESULT_ERROR_CODE(NONE, 0, MSG, IS_MSG_ON_HEAP);
#define RESULT_ERROR_LITERAL(MSG) \
RESULT_ERROR(STR((MSG)), false)
#define RESULT_ERROR_FMT(FORMAT, ARGS...) \ #define RESULT_ERROR_FMT(FORMAT, ARGS...) \
RESULT_ERROR_CODE_FMT(NONE, 0, FORMAT ,##ARGS) RESULT_ERROR_CODE_FMT(NONE, 0, FORMAT ,##ARGS)
#define RESULT_ERROR_ERRNO() \ #define RESULT_ERROR_ERRNO() \
RESULT_ERROR_CODE(LIBC_ERRNO, errno, strerror_malloc(errno), true) RESULT_ERROR_CODE(LIBC_ERRNO, errno, str_from_cstr(strerror_malloc(errno)), true)
#define RESULT_VOID (Result_){ .error = NULL, .u = 0 } #define RESULT_VOID (Result_){ .error = NULL, .u = 0 }
#define RESULT_VALUE(FIELD, V) (Result_){ .error = NULL, .FIELD = V } #define RESULT_VALUE(FIELD, V) (Result_){ .error = NULL, .FIELD = V }
#define try(VAR, RESULT_FIELD, RSLT_CALL) \
_try(VAR, RESULT_FIELD, RSLT_CALL, __LINE__)
#define try_void(RSLT_CALL) \
_try_void(RSLT_CALL, __LINE__)
#define try_fatal(VAR, RESULT_FIELD, RSLT_CALL) \
_try_fatal(VAR, RESULT_FIELD, RSLT_CALL, __LINE__)
#define try_fatal_void(RSLT_CALL) \
_try_fatal_void(RSLT_CALL, __LINE__)
#define try_handle(VAR, RESULT_FIELD, RSLT_CALL, HANDLER) \
_try_handle(VAR, RESULT_FIELD, RSLT_CALL, HANDLER, __LINE__)
#define try_handle_void(RSLT_CALL, HANDLER) \
_try_handle_void(RSLT_CALL, HANDLER, __LINE__)
#define try_stderrcode(RSLT_CALL) \
_try_stderrcode(RSLT_CALL, __LINE__)
#define try_fatal_stderrcode(RSLT_CALL) \
_try_fatal_stderrcode(RSLT_CALL, __LINE__)
#define _rname(N) __r_##N #define _rname(N) __r_##N
#define try(VAR, RESULT_FIELD, RSLT_CALL) _try(VAR, RESULT_FIELD, RSLT_CALL, __LINE__) #define _try_handle(VAR, RESULT_FIELD, RSLT_CALL, HANDLER, N) \
#define try_fatal(VAR, RESULT_FIELD, RSLT_CALL) _try_fatal(VAR, RESULT_FIELD, RSLT_CALL, __LINE__) Result_ _rname(N) = RSLT_CALL;\
#define try_void(RSLT_CALL) _try_void(RSLT_CALL, __LINE__) if(_rname(N).error){\
#define try_fatal_void(RSLT_CALL) _try_fatal_void(RSLT_CALL, __LINE__) Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
#define try_stderrcode(RSLT_CALL) _try_stderrcode(RSLT_CALL, __LINE__) HANDLER(_rname(N));\
#define try_fatal_stderrcode(RSLT_CALL) _try_fatal_stderrcode(RSLT_CALL, __LINE__) }\
VAR = _rname(N).RESULT_FIELD;
#define _try_handle_void(RSLT_CALL, HANDLER, N) \
Result_ _rname(N) = RSLT_CALL;\
if(_rname(N).error){\
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
HANDLER(_rname(N));\
}\
#define _try__handler(R) Return R
#define _try(VAR, RESULT_FIELD, RSLT_CALL, N) \ #define _try(VAR, RESULT_FIELD, RSLT_CALL, N) \
Result_ _rname(N) = RSLT_CALL;\ _try_handle(VAR, RESULT_FIELD, RSLT_CALL, _try__handler, N)
if(_rname(N).error){\ #define _try_void(RSLT_CALL, N) \
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\ _try_handle_void(RSLT_CALL, _try__handler, N)
Return _rname(N);\
};\
VAR = _rname(N).RESULT_FIELD;
#define _try_void(RSLT_CALL, N) do {\
Result_ _rname(N) = RSLT_CALL;\
if(_rname(N).error){\
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
Return _rname(N);\
};\
} while(0)
#define _try_fatal__handler(R) Error_printAndExit(R.error)
#define _try_fatal(VAR, RESULT_FIELD, RSLT_CALL, N) \ #define _try_fatal(VAR, RESULT_FIELD, RSLT_CALL, N) \
Result_ _rname(N) = RSLT_CALL;\ _try_handle(VAR, RESULT_FIELD, RSLT_CALL, _try_fatal__handler, N)
if(_rname(N).error){\ #define _try_fatal_void(RSLT_CALL, N) \
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\ _try_handle_void(RSLT_CALL, _try_fatal__handler, N)
Error_printAndExit(_rname(N).error);\
};\
VAR = _rname(N).RESULT_FIELD;
#define _try_fatal_void(RSLT_CALL, N) do {\ #define _try_stderrcode(CALL, N) \
Result_ _rname(N) = RSLT_CALL;\
if(_rname(N).error){\
Error_addCallPos(_rname(N).error, ErrorCallPos_here());\
Error_printAndExit(_rname(N).error);\
};\
} while(0)
#define _try_stderrcode(CALL, N) do {\
int _rname(N) = CALL;\ int _rname(N) = CALL;\
if(_rname(N) != 0){\ if(_rname(N) != 0){\
Return RESULT_ERROR_CODE(LIBC_ERRNO, _rname(N), strerror_malloc(_rname(N)), true);\ Return RESULT_ERROR_CODE(LIBC_ERRNO, _rname(N), str_from_cstr(strerror_malloc(_rname(N))), true);\
}\ }\
} while(0)
#define _try_fatal_stderrcode(CALL, N) do {\ #define _try_fatal_stderrcode(CALL, N) \
int _rname(N) = CALL;\ int _rname(N) = CALL;\
if(_rname(N) != 0){\ if(_rname(N) != 0){\
Error_printAndExit(Error_create(\ Error_printAndExit(Error_create(\
strerror_malloc(_rname(N)), true, ErrorCallPos_here(), \ str_from_cstr(strerror_malloc(_rname(N))), true, \
ErrorCallPos_here(), \
ErrorCodePage_name(LIBC_ERRNO), _rname(N)\ ErrorCodePage_name(LIBC_ERRNO), _rname(N)\
));\ ));\
}\ }\
} while(0)
#define try_assert(EXPR) if(!(EXPR)) { Return RESULT_ERROR(("assertion must be true: " #EXPR), false); } #define try_assert(EXPR) if(!(EXPR)) { Return RESULT_ERROR_LITERAL("assertion must be true: " #EXPR); }

View File

@@ -39,6 +39,8 @@ str path_dirname(str path);
/// @return pointer to a segment of path.data or path itself if no path_sep has been found /// @return pointer to a segment of path.data or path itself if no path_sep has been found
str path_basename(str path, bool remove_ext); str path_basename(str path, bool remove_ext);
/// @return heap-allocated string
Result(char*) path_getUserDir();
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// FILE // // FILE //
@@ -145,8 +147,15 @@ Result(void) file_readWholeText(FILE* f, str* out_str);
// DIRECTORY // // DIRECTORY //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @return true if directory exists or `path` is null or empty or '.' or './'
bool dir_exists(cstr path); bool dir_exists(cstr path);
/// @brief creates directories specified in path recursively /// @brief creates directories specified in path recursively
/// EXAMPLE: dir_createParent("a/b/c") -> creates "a", "a/b", "a/b/c"
/// @return false if directory was present already, true if it has been created /// @return false if directory was present already, true if it has been created
Result(bool) dir_create(cstr path); Result(bool) dir_create(cstr path);
/// @brief creates directories except the last part of path
/// EXAMPLE: dir_createParent("a/b/c") -> creates "a", "a/b"
/// @return false if directory was present already, true if it has been created
Result(bool) dir_createParent(cstr path);

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#if __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@@ -59,6 +59,8 @@ typedef void (*Destructor_t)(void* self);
#define dbg(N) printf("\e[95m%d\n",N) #define dbg(N) printf("\e[95m%d\n",N)
#define nameof(V) #V #define nameof(V) #V
#define CAT2(a, b) a ## b
#define CAT3(a, b, c) a ## b ## c
#define ARRAY_LEN(A) (sizeof(A)/sizeof(A[0])) #define ARRAY_LEN(A) (sizeof(A)/sizeof(A[0]))
#define ALIGN_TO(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1)) #define ALIGN_TO(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1))
@@ -122,6 +124,24 @@ typedef void (*Destructor_t)(void* self);
#define ATTRIBUTE_THREAD_LOCAL __thread #define ATTRIBUTE_THREAD_LOCAL __thread
#endif #endif
#if __cplusplus #ifdef _MSC_VER
#define PRAGMA_WARNING_PUSH __pragma(warning( push ))
#define PRAGMA_WARNING_POP __pragma(warning( pop ))
#define PRAGMA_WARNING_DISABLE(wNumber) __pragma(warning( disable : wNumber ))
#define W_RETURN_TYPE
#else
#define _PRAGMA(P) _Pragma(#P)
#define PRAGMA_WARNING_PUSH _PRAGMA(GCC diagnostic push)
#define PRAGMA_WARNING_POP _PRAGMA(GCC diagnostic pop)
#define PRAGMA_WARNING_DISABLE(wName) _PRAGMA(GCC diagnostic ignored wName)
#define W_RETURN_TYPE "-Wreturn-type"
#endif
#define WARNING_DISABLE(WARNING, CODE...) \
PRAGMA_WARNING_PUSH \
PRAGMA_WARNING_DISABLE(WARNING) \
CODE; \
PRAGMA_WARNING_POP
#ifdef __cplusplus
} }
#endif #endif

View File

@@ -16,10 +16,10 @@ typedef struct str {
/* /*
USAGE: USAGE:
str s = STR("something"); str s = STR("something");
printf(FMT_str"\n", str_expand(s)); printf(FMT_str"\n", str_unwrap(s));
*/ */
#define FMT_str "%.*s" #define FMT_str "%.*s"
#define str_expand(S) (S).len, (S).data #define str_unwrap(S) (S).len, (S).data
/// creates str from a string literal /// creates str from a string literal
#define STR(LITERAL) str_construct(LITERAL, ARRAY_LEN(LITERAL) - 1, true) #define STR(LITERAL) str_construct(LITERAL, ARRAY_LEN(LITERAL) - 1, true)
@@ -59,7 +59,7 @@ static inline str Array_u8_castTo_str(Array(u8) a, bool isZeroTerminated) {
static const str str_null = str_construct(NULL, 0, 0); static const str str_null = str_construct(NULL, 0, 0);
/// copies src content to new string and adds \0 at the end /// copy str data to new str and add \0 at the end
str str_copy(const str self); str str_copy(const str self);
/// compares two strings, NullPtr-friendly /// compares two strings, NullPtr-friendly

View File

@@ -1,10 +1,10 @@
#pragma once #pragma once
#if __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "std.h" #include "errors.h"
/// nanoseconds /// nanoseconds
typedef u64 nsec_t; typedef u64 nsec_t;
@@ -52,10 +52,15 @@ void DateTime_get(DateTime* dt, bool utc_time);
static inline void DateTime_getLocal(DateTime* dt) { DateTime_get(dt, false); } static inline void DateTime_getLocal(DateTime* dt) { DateTime_get(dt, false); }
static inline void DateTime_getUTC(DateTime* dt) { DateTime_get(dt, true); } static inline void DateTime_getUTC(DateTime* dt) { DateTime_get(dt, true); }
// yyyy.MM.dd_HH-mm-ss /// yyyy.MM.dd HH:mm:ss_float
Result(void) DateTime_parse(cstr src, DateTime* dt);
/// yyyy.MM.dd_HH-mm-ss
#define FMT_DateTime_fileName "%04i.%02i.%02i_%02i-%02i-%02i" #define FMT_DateTime_fileName "%04i.%02i.%02i_%02i-%02i-%02i"
// yyyy.MM.dd HH:mm:ss /// yyyy.MM.dd HH:mm:ss
#define FMT_DateTime_text "%04i.%02i.%02i %02i:%02i:%02i" /// yyyy.MM.dd HH:mm:ss_float
#define FMT_DateTime_text "%04i.%02i.%02i-%02i:%02i:%02i"
#define FMT_DateTime_text_subsec FMT_DateTime_text".%09i"
/* /*
USAGE: USAGE:
DateTime dt; DateTime dt;
@@ -63,8 +68,8 @@ USAGE:
printf(FMT_DateTime_text, DT_expand(dt)); printf(FMT_DateTime_text, DT_expand(dt));
*/ */
#define DT_expand(dt) dt.d.year, dt.d.month, dt.d.month_day, dt.t.hour, dt.t.min, dt.t.sec #define DT_expand(dt) dt.d.year, dt.d.month, dt.d.month_day, dt.t.hour, dt.t.min, dt.t.sec
#define DT_expand_subsec(dt) dt.d.year, dt.d.month, dt.d.month_day, dt.t.hour, dt.t.min, dt.t.sec, dt.t.nsec
#ifdef __cplusplus
#if __cplusplus
} }
#endif #endif

View File

@@ -43,7 +43,7 @@ case "$OS" in
EXEC_FILE="$PROJECT.exe" EXEC_FILE="$PROJECT.exe"
SHARED_LIB_FILE="$PROJECT.dll" SHARED_LIB_FILE="$PROJECT.dll"
INCLUDE="$INCLUDE " INCLUDE="$INCLUDE "
LINKER_LIBS="" LINKER_LIBS="-luuid"
;; ;;
LINUX) LINUX)
EXEC_FILE="$PROJECT" EXEC_FILE="$PROJECT"

View File

@@ -225,6 +225,6 @@ bool HashMapIter_getCurrent(HashMapIter* self, HashMapKeyValue* kv){
return false; return false;
kv->key = bu->key_hash_list.data[self->elem_n].key; kv->key = bu->key_hash_list.data[self->elem_n].key;
kv->value = (u8*)bu->value_list.data + self->map->value_t_size * self->elem_n; kv->value_ptr = (u8*)bu->value_list.data + self->map->value_t_size * self->elem_n;
return true; return true;
} }

View File

@@ -3,11 +3,11 @@
#define ERRMSG_LENGTH 1024 #define ERRMSG_LENGTH 1024
Error* Error_create(const char* msg, bool is_msg_on_heap, ErrorCallPos p, Error* Error_create(str msg, bool is_msg_on_heap, ErrorCallPos p,
u16 error_code_page, u32 error_code) u16 error_code_page, u32 error_code)
{ {
Error* e = (Error*)malloc(sizeof(Error)); Error* e = (Error*)malloc(sizeof(Error));
e->msg = str_construct((char*)(void*)msg, strlen(msg), true); e->msg = msg;
e->is_msg_on_heap = is_msg_on_heap; e->is_msg_on_heap = is_msg_on_heap;
e->error_code_page = error_code_page; e->error_code_page = error_code_page;
e->error_code = error_code; e->error_code = error_code;

View File

@@ -1,6 +1,9 @@
#include "internal.h" #include "internal.h"
bool dir_exists(cstr path){ bool dir_exists(cstr path){
if(path == NULL || path[0] == 0)
return true;
if(path[0]=='.'){ if(path[0]=='.'){
if(path[1]==0 || (path[1]==path_sep && path[1]==0)) if(path[1]==0 || (path[1]==path_sep && path[1]==0))
return true; // dir . or ./ always exists return true; // dir . or ./ always exists
@@ -23,13 +26,12 @@ bool dir_exists(cstr path){
Result(bool) dir_create(cstr path){ Result(bool) dir_create(cstr path){
Deferral(4); Deferral(4);
if (dir_exists(path)){
if (path == NULL || path[0] == 0 || dir_exists(path)){
Return RESULT_VALUE(i, false); Return RESULT_VALUE(i, false);
} }
char* parentDir= str_copy(path_dirname(str_from_cstr((void*)path))).data; try_void(dir_createParent(path));
Defer(free(parentDir));
try_void(dir_create(parentDir));
#if TLIBC_FS_USE_WINDOWS_H #if TLIBC_FS_USE_WINDOWS_H
if(!CreateDirectory(path, NULL)) if(!CreateDirectory(path, NULL))
@@ -47,3 +49,18 @@ Result(bool) dir_create(cstr path){
Return RESULT_VALUE(i, true); Return RESULT_VALUE(i, true);
} }
Result(bool) dir_createParent(cstr path){
Deferral(4);
str parent_dir_str = path_dirname(str_from_cstr((void*)path));
if(parent_dir_str.len == 0){
Return RESULT_VALUE(i, false);
}
char* parent_dir_cstr = str_copy(parent_dir_str).data;
Defer(free(parent_dir_cstr));
try(bool result, i, dir_create(parent_dir_cstr));
Return RESULT_VALUE(i, result);
}

View File

@@ -1,4 +1,10 @@
#include "tlibc/filesystem.h" #include "internal.h"
#if TLIBC_FS_USE_WINDOWS_H
#include <knownfolders.h>
#include <shlobj.h>
#else
#endif
str path_dirname(str path){ str path_dirname(str path){
if(path.len == 0) if(path.len == 0)
@@ -43,3 +49,23 @@ str path_basename(str path, bool remove_ext){
} }
return path; return path;
} }
Result(char*) path_getUserDir(){
#if TLIBC_FS_USE_WINDOWS_H
PWSTR wpath = NULL;
HRESULT reslut = SHGetKnownFolderPath(&FOLDERID_Profile, 0, NULL, &wpath);
if(!SUCCEEDED(reslut)){
return RESULT_ERROR_LITERAL("can't get user directory by SHGetKnownFolderPath()");
}
size_t char_len = wcslen(wpath) * 4 + 1;
char* path = (char*)malloc(char_len);
wcstombs(path, wpath, char_len);
return RESULT_VALUE(p, path);
#else
const char *home = getenv("HOME");
if(home == NULL){
return RESULT_ERROR_LITERAL("can't get user directory by getenv(\"HOME\")");
}
return RESULT_VALUE(p, cstr_copy(home));
#endif
}

View File

@@ -2,11 +2,10 @@
#include "tlibc/string/StringBuilder.h" #include "tlibc/string/StringBuilder.h"
str str_copy(const str self){ str str_copy(const str self){
if(self.data == NULL || self.len == 0)
return self;
str copy = str_construct((char*)malloc(self.len + 1), self.len, true); str copy = str_construct((char*)malloc(self.len + 1), self.len, true);
memcpy(copy.data, self.data, self.len); if(self.len != 0){
memcpy(copy.data, self.data, self.len);
}
copy.data[copy.len] = '\0'; copy.data[copy.len] = '\0';
return copy; return copy;
} }

View File

@@ -71,3 +71,17 @@ void DateTime_get(DateTime* dt, bool utc_time){
dt->d.week_day = c_tm.tm_wday + 1; dt->d.week_day = c_tm.tm_wday + 1;
dt->d.year_day = c_tm.tm_yday + 1; dt->d.year_day = c_tm.tm_yday + 1;
} }
Result(void) DateTime_parse(cstr src, DateTime* dt){
zeroStruct(dt);
f64 sec_f = 0;
i32 r = sscanf(src, "%"SCNi16".%"SCNi8".%"SCNi8"-%"SCNi8":%"SCNi8":%lf",
&dt->d.year, &dt->d.month, &dt->d.month_day,
&dt->t.hour, &dt->t.min, &sec_f);
if(r != 6){
return RESULT_ERROR_FMT("attepmted to parse DateTime, got %i fields out of 6", r);
}
dt->t.sec = (i32)sec_f;
dt->t.nsec = (sec_f - (i32)sec_f) * 1e9;
return RESULT_VOID;
}