/* vim: set filetype=c : */ #ifndef LIB_H # define LIB_H # ifndef _STDINT_H # define LIB_H_STDINT # define intmax_t long int # endif /* _STDINT_H */ # ifndef _UNISTD_H # define LIB_H_UNISTD # define R_OK 4 # define W_OK 2 # define X_OK 1 # define F_OK 0 # endif /* _UNISTD_H */ # ifndef NULL # define LIB_H_NULL # define NULL ((void *) 0) # endif /* NULL */ # ifndef _STDBOOL_H # define LIB_H_STDBOOL # define bool unsigned char # define true 1 # define false 0 # endif /* _STDBOOL_H */ /* --------------------------- START GLOBAL DEF ---------------------------- */ # define ALLOC_FUNC void *(*alloc)(u64) # define FREE_FUNC void (*free)(void *) # define MACRO_STR_CONCAT_X(lhs, rhs) lhs ## rhs # define MACRO_STR_CONCAT(lhs, rhs) MACRO_STR_CONCAT_X(lhs, rhs) # define MACRO_STR_VALUE(arg) #arg # define MACRO_STR_VALUE_X(arg) MACRO_STR_VALUE(arg) # define BOOL2CSTR(bool) ((bool) ? "True" : "False") # define UNUSED(arg) (void) arg enum err { ERR_OK = 0, ERR_GENERAL_ERROR, ERR_NOT_INT, ERR_TOO_BIG, ERR_NULL_ARG, ERR_INVALID_ARG, ERR_NOT_FOUND, ERR_INDEX_TOO_LARGE, ERR_FAILED_OPEN, ERR_FAILED_CLOSE, ERR_FAILED_READ, ERR_FAILED_WRITE, ERR_FAILED_FORK, ERR_FAILED_WAITPID, ERR_WROTE_WRONG_AMOUNT, ERR_FAILED_ALLOC, ERR_FAILED_REALLOC, ERR_MKDIR_FAILED, ERR_FAILED_HASHING, ERR_STR_EMPTY, ERR_PATH_EMPTY, ERR_PATH_INVALID, ERR_PATH_FILE_EMPTY, ERR_PATH_FILE_FAILED_SEEK, ERR_CMD_NON_ZERO_EXIT_CODE, ERR_SGFX_POS_OUTSIDE_CANVAS }; const char *err_to_name[] = { "ERR_OK", "ERR_GENERAL_ERROR", "ERR_NOT_INT", "ERR_TOO_BIG", "ERR_NULL_ARG", "ERR_INVALID_ARG", "ERR_NOT_FOUND", "ERR_INDEX_TOO_LARGE", "ERR_FAILED_OPEN", "ERR_FAILED_CLOSE", "ERR_FAILED_READ", "ERR_FAILED_WRITE", "ERR_FAILED_FORK", "ERR_FAILED_WAITPID", "ERR_WROTE_WRONG_AMOUNT", "ERR_FAILED_ALLOC", "ERR_FAILED_REALLOC", "ERR_MKDIR_FAILED", "ERR_FAILED_HASHING", "ERR_STR_EMPTY", "ERR_PATH_EMPTY", "ERR_PATH_INVALID", "ERR_PATH_FILE_EMPTY", "ERR_PATH_FILE_FAILED_SEEK", "ERR_CMD_NON_ZERO_EXIT_CODE", "ERR_SGFX_POS_OUTSIDE_CANVAS", }; /* ---------------------------- END GLOBAL DEF ----------------------------- */ /* ----------------------------- START INT DEF ----------------------------- */ typedef long int i64; typedef unsigned long int u64; typedef int i32; typedef unsigned int u32; typedef short int i16; typedef unsigned short int u16; typedef char i8; typedef unsigned char u8; /* ------------------------------ END INT DEF ------------------------------ */ void *malloc(u64 size); void *realloc(void *ptr, u64 new_size); void free(void *ptr); void *memcpy(void *dest, const void *src, u64 n); void *memset(void *s, int c, u64 n); char *getenv(const char *name); void abort(void); void exit(int exit_code); int execve(const char *path, char *const argv[], char *const envp[]); int fork(void); # ifndef WIFEXITED # error "Must import before lib.h!" # endif /* ----------------------------- START LIB DEF ----------------------------- */ # define TODO(msg) \ do { \ fprintf(stderr, "%s:%d "msg"\n", __FILE__, __LINE__); \ abort(); \ } while(0); # define LIB_COALESCE2(arg1, arg2) ((arg1 != Null) ? arg1 : arg2) # define LIB_SET_IF_NULL(var, val) \ if ( (var) == NULL ) { \ (var) = (val); \ } # define LIB_SET_IF_NOT_NULL(var, err) \ if ( var != NULL ) { \ *var = err; \ } # define LIB_ARG_IF_NOT_NULL_MUST_BE(arg, val, ret_val) \ if ( arg != NULL ) { \ if ( *arg != val ) { \ return ret_val; \ } \ } # define LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(arg, val) \ if ( arg != NULL ) { \ if ( *arg != val ) { \ return *arg; \ } \ } # define LIB_ARG_MUST_NOT_BE_NULL_RET_ERR(arg) \ if ( (arg) == NULL ) { \ return ERR_NULL_ARG; \ } # define LIB_ARG_MUST_NOT_BE_NULL(arg, err_var, ret_val) \ if ( (arg) == NULL ) { \ LIB_SET_IF_NOT_NULL(err_var, ERR_NULL_ARG); \ return ret_val; \ } # define LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(arg, err_var) \ if ( (arg) == NULL ) { \ LIB_SET_IF_NOT_NULL(err_var, ERR_NULL_ARG); \ return ERR_NULL_ARG; \ } # define LIB_STR_MUST_NOT_BE_EMPTY(arg, err_var, ret_val) \ if ( (arg).data == NULL || (arg).size == 0 ) { \ LIB_SET_IF_NOT_NULL(err_var, ERR_STR_EMPTY); \ return ret_val; \ } # define _r_ __restrict__ # define SIZEOF_MEMBER(Struct, Member) sizeof(((Struct *)0)->Member) # define CAST(Type, Var) ((Type) (Var)) # define LIB_FREE lib_free void lib_free(const void *ptr); # if defined(IMP) || defined(IMP_LIB) void lib_free(const void *ptr) { if ( ptr == NULL ) return; free((void *)ptr); } # endif /* defined(IMP) || defined(IMP_LIB) */ /* ------------------------------ END LIB DEF ------------------------------ */ /* ----------------------------- START VEC DEF ----------------------------- */ # if defined(WANT_VEC2) || defined(WANT_ALL) # define _VEC2_STRUCT_DEF(type) \ struct MACRO_STR_CONCAT(type, vec2) { \ type x, y; \ }; \ struct MACRO_STR_CONCAT(type, vec2s) { \ type w, h; \ } _VEC2_STRUCT_DEF(i64); _VEC2_STRUCT_DEF(u64); _VEC2_STRUCT_DEF(i32); _VEC2_STRUCT_DEF(u32); _VEC2_STRUCT_DEF(i16); _VEC2_STRUCT_DEF(u16); _VEC2_STRUCT_DEF(i8); _VEC2_STRUCT_DEF(u8); # undef _VEC2_STRUCT_DEF # endif /* defined(WANT_VEC2) || defined(WANT_ALL) */ /* ------------------------------ END VEC DEF ------------------------------ */ /* ---------------------------- START CSTR DEF ----------------------------- */ # if defined(WANT_CSTR) || defined(WANT_ALL) u64 cstr_len_max(const char *cstr, u64 max, bool *out_hit_max, enum err *out_err); # endif /* defined(WANT_CSTR) || defined(WANT_ALL) */ /* ----------------------------- END CSTR DEF ------------------------------ */ /* ---------------------------- START STR DEF ------------------------------ */ # if defined(WANT_STR) || defined(WANT_ALL) # ifndef STR_SIZE_LIMIT # define STR_SIZE_LIMIT 1028 # endif /* STR_SIZE_LIMIT */ # define STR_DESTROY(Str) \ if ( (Str).should_be_freed == true ) LIB_FREE((Str).data) # define DA2STR(Da, Str) \ (Str).data = (Da).data; \ (Str).size = (Da).size; \ (Str).should_be_freed = true; struct str { const char *data; u64 size; bool should_be_freed; }; const struct str STR_EMPTY = {"", 0, false}; struct str_tokenizer { struct str str; u64 cur; char c; bool (*f)(char c); }; struct str str_from_cstr(const char *cstr, u64 cstr_size, enum err *out_err); struct str str_from_cstr_ns(const char *cstr, enum err *out_err); struct str str_from_i64(i64 num, enum err *out_err); struct str str_from_i64_temp(i64 num); struct str str_dup(struct str str); struct str str_replace_escape_chars(const struct str *str, enum err *out_err); intmax_t str_to_int(struct str str, enum err *err); struct str str_rstrip(struct str str); struct str str_lstrip(struct str str); struct str str_strip(struct str str); u64 str_lindex(struct str str, char c); u64 str_rindex(struct str str, char c); struct str_tokenizer str_tokenize(struct str str, char c); struct str_tokenizer str_tokenize_func(struct str str, bool (*f)(char c)); struct str str_tokenizer_next(struct str_tokenizer *st); struct str str_slice(struct str str, u64 from, u64 to); bool str_eq_cstr(struct str str, const char *cstr, u64 cstr_size); bool str_eq_str(struct str str1, struct str str2); bool str_startswith_cstr(struct str str, const char *cstr, u64 cstr_size); bool str_is_int(struct str str); struct str_builder { char *data; u64 size; u64 cap; }; struct str str_builder_to_str(const struct str_builder *str_bldr); # if defined(IMP) || defined(IMP_STR) struct str str_replace_escape_chars(const struct str *str, enum err *out_err) { struct str empty = {0}; struct str_builder ret = {0}; u64 i = 0; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); LIB_ARG_MUST_NOT_BE_NULL(str, out_err, empty); LIB_STR_MUST_NOT_BE_EMPTY(*str, out_err, empty); ret.data = malloc(str->size); ret.size = 0; if ( ret.data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); return empty; } memset((void*)ret.data, 0, str->size); for ( i = 0; i < str->size; ++i ) { if ( str->data[i] == '\\' ) { if ( (i+1) < str->size ) { ++i; switch ( str->data[i] ) { case 'n': ret.data[ret.size++] = '\n'; break; case 'r': ret.data[ret.size++] = '\r'; break; case 't': ret.data[ret.size++] = '\t'; break; case 'e': ret.data[ret.size++] = '\033'; break; default: ret.data[ret.size++] = '\\'; ret.data[ret.size++] = str->data[i]; break; } continue; } } ret.data[ret.size++] = str->data[i]; } return str_builder_to_str(&ret); } # endif /* defined(IMP) || defined(IMP_STR) */ # endif /* defined(WANT_STR) || defined(WANT_ALL) */ /* ----------------------------- END STR DEF ------------------------------- */ /* -------------------------- START DYN ARR DEF ---------------------------- */ # if defined(WANT_DYN_ARR) || defined(WANT_ALL) struct dyn_arr { void *data; u64 size; u64 cap; u16 elem_size; }; struct dyn_arr dyn_arr_create(u16 elem_size, enum err *out_err); enum err dyn_arr_append(struct dyn_arr *da, void *elem, enum err *out_err); enum err dyn_arr_prepend(struct dyn_arr *da, void *elem, enum err *out_err); enum err dyn_arr_insert(struct dyn_arr *da, void *elem, u64 index, enum err *out_err); void *dyn_arr_pop(struct dyn_arr *da, u64 index, enum err *out_err); void *dyn_arr_pop_last(struct dyn_arr *da, enum err *out_err); enum err dyn_arr_destroy(struct dyn_arr *da, enum err *out_err); # if defined(IMP) || defined(IMP_DYN_ARR) struct dyn_arr dyn_arr_create(u16 elem_size, enum err *out_err) { struct dyn_arr empty = {0}; struct dyn_arr da = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); da.size = 0; da.cap = 64; da.elem_size = elem_size; da.data = malloc(da.elem_size * da.cap); if ( da.data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); return empty; } memset(da.data, 0, elem_size * da.cap); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return da; } enum err dyn_arr_insert(struct dyn_arr *da, void *elem, u64 index, enum err *out_err) { u64 new_size = 0; u64 i = 0; u8 *data = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da->data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(elem, out_err); new_size = da->size + 1; if ( index >= new_size ) { LIB_SET_IF_NOT_NULL(out_err, ERR_INDEX_TOO_LARGE); return ERR_INDEX_TOO_LARGE; } if ( new_size >= da->cap ) { da->cap *= 2; da->data = realloc(da->data, da->cap); if ( da->data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); return ERR_FAILED_ALLOC; } } data = (u8*) da->data; if ( da->size > 0 ) { for ( i = da->size-1; i > index; i-- ) { memcpy((data + i), (data + i - 1), da->elem_size); } } memcpy((data + index), elem, da->elem_size); ++da->size; LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } enum err dyn_arr_append(struct dyn_arr *da, void *elem, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da->data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(elem, out_err); return dyn_arr_insert(da, elem, da->size, out_err); } enum err dyn_arr_prepend(struct dyn_arr *da, void *elem, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da->data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(elem, out_err); return dyn_arr_insert(da, elem, 0, out_err); } void * dyn_arr_pop(struct dyn_arr *da, u64 index, enum err *out_err) { static u8 temp_mem[256] = {0}; u8 *data = NULL; u64 i = 0; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, NULL); LIB_ARG_MUST_NOT_BE_NULL(da, out_err, NULL); LIB_ARG_MUST_NOT_BE_NULL(da->data, out_err, NULL); if ( index >= da->size ) { LIB_SET_IF_NOT_NULL(out_err, ERR_INDEX_TOO_LARGE); return NULL; } data = (u8*) da->data; memcpy(temp_mem, (data + index), da->elem_size); for ( i = index; i < da->size-1; ++i ) { memcpy((data + i), (data + i + 1), da->elem_size); } --da->size; LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return temp_mem; } void * dyn_arr_pop_last(struct dyn_arr *da, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, NULL); LIB_ARG_MUST_NOT_BE_NULL(da, out_err, NULL); LIB_ARG_MUST_NOT_BE_NULL(da->data, out_err, NULL); return dyn_arr_pop(da, da->size-1, out_err); } enum err dyn_arr_destroy(struct dyn_arr *da, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(da->data, out_err); free(da->data); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } # endif /* defined(IMP) || defined(IMP_DYN_ARR) */ # endif /* defined(WANT_DYN_ARR) || defined(WANT_ALL) */ /* --------------------------- END DYN ARR DEF ----------------------------- */ /* ---------------------------- START DA DEF ------------------------------- */ # define DA_FOREACH(Da, Var) \ for ( typeof((Da).data) (Var) = (Da).data; \ (Var) < ((Da).data + (Da).size); \ ++(Var) ) # define DA_FOREACH_INDEX(Da, VarI) \ for ( typeof((Da).size) (VarI) = 0; \ (VarI) < (Da).size; \ ++(VarI) ) # define DA_APPEND(da, val, err_var) \ do { \ if ( err_var != NULL ) { \ if ( *err_var != ERR_OK ) { \ break; \ } \ } \ if ( (da).size + 1 >= (da).cap ) { \ (da).cap *= 2; \ (da).data = realloc((da).data, (da).cap); \ if ( (da).data == NULL ) { \ LIB_SET_IF_NOT_NULL((err_var), ERR_FAILED_REALLOC); \ break; \ } \ } \ if ( (da).data == NULL ) { \ if ( (da).cap == 0 ) { \ (da).cap = 32; \ (da).size = 0; \ } \ (da).data = malloc(sizeof(*(da).data) * (da).cap); \ if ( (da).data == NULL ) { \ LIB_SET_IF_NOT_NULL((err_var), ERR_FAILED_ALLOC); \ break; \ } \ memset((da).data, 0, sizeof(*(da).data) * (da).cap); \ } \ (da).data[(da).size++] = (val); \ LIB_SET_IF_NOT_NULL((err_var), ERR_OK); \ } while(0) # define DA_APPEND_DATA(Da, Val, ItemNum, ErrVar) \ do { \ if ( (ErrVar) != NULL ) { \ if ( *(ErrVar) != ERR_OK ) { \ break; \ } \ } \ if ( (Da).size + (ItemNum) >= (Da).cap ) { \ (Da).cap += (ItemNum); \ (Da).cap *= 2; \ (Da).data = realloc((Da).data, (Da).cap); \ if ( (Da).data == NULL ) { \ LIB_SET_IF_NOT_NULL((ErrVar), ERR_FAILED_REALLOC); \ break; \ } \ } \ if ( (Da).data == NULL ) { \ if ( (Da).cap == 0 ) { \ (Da).cap = (ItemNum) * 2; \ (Da).size = 0; \ } \ (Da).data = malloc(sizeof(*(Da).data) * (Da).cap); \ if ( (Da).data == NULL ) { \ LIB_SET_IF_NOT_NULL((ErrVar), ERR_FAILED_ALLOC); \ break; \ } \ } \ memcpy((Da).data, (Val), sizeof(*(Da).data) * (ItemNum)); \ (Da).size += ItemNum; \ LIB_SET_IF_NOT_NULL((ErrVar), ERR_OK); \ } while(0) # define DAV_APPEND(Da, Val, ValSize, ErrVar) \ do { \ if ( ErrVar != NULL ) { \ if ( *ErrVar != ERR_OK ) { \ break; \ } \ } \ /* printf("ValSize -> %5ld\tused_bytes -> %5ld\tcap_bytes -> %5ld\n", (ValSize), (Da).used_bytes, (Da).cap_bytes); */ \ if ( (Da).used_bytes + (ValSize) >= (Da).cap_bytes ) { \ (Da).cap_bytes *= 2; \ (Da).data = realloc((Da).data, (Da).cap_bytes); \ if ( (Da).data == NULL ) { \ LIB_SET_IF_NOT_NULL((ErrVar), ERR_FAILED_REALLOC); \ break; \ } \ } \ if ( (Da).data == NULL ) { \ if ( (Da).cap_bytes == 0 ) { \ (Da).cap_bytes = 32; \ (Da).size = 0; \ (Da).used_bytes = 0; \ } \ (Da).data = malloc(sizeof(u64) * (Da).cap_bytes); \ if ( (Da).data == NULL ) { \ LIB_SET_IF_NOT_NULL((ErrVar), ERR_FAILED_ALLOC); \ break; \ } \ } \ memcpy(CAST(u8*, (Da).data) + (Da).used_bytes, (Val), (ValSize)); \ (Da).used_bytes += (ValSize); \ ++(Da).size; \ LIB_SET_IF_NOT_NULL((ErrVar), ERR_OK); \ } while(0) /* ----------------------------- END DA DEF -------------------------------- */ /* ---------------------------- START MAP DEF ------------------------------ */ # if defined(WANT_MAP) || defined(WANT_ALL) # define MAP_FOR_EACH(Map, VIndex, VKey) \ for ( (VIndex = (Map)->indexs.data, VKey = (Map)->keys.data); \ VIndex < ((Map)->indexs.data + (Map)->indexs.size); \ (++VIndex, VKey = CAST(struct key_bytes *, CAST(u8*, VKey->key) + VKey->size)) ) # define MAP_FOR_EACH_INDEXS(Map, Var) \ for ( Var = (Map)->indexs.data; \ Var < ((Map)->indexs.data + (Map)->indexs.size); \ ++Var ) # define MAP_GET_INDEX(Map, Index) \ ((struct map_item *)(((u8*)(Map)->data) + ((Map)->_item_size * (Index)))) struct key_bytes { u64 size; u8 key[1]; }; struct map_item { u64 key[4]; u8 item[1]; }; struct map { struct map_item *data; u64 size; struct { u64 *data; u64 size; u64 cap; } indexs; struct { struct key_bytes *data; u64 size; u64 used_bytes; u64 cap_bytes; } keys; u64 _cap; u64 _size_bytes; u64 _item_size; u64 _elem_size; u64 *(*hash)(void *key, u64 key_size); }; struct map map_create(u64 elem_size, u64 cap, enum err *_r_ out_err); enum err map_inc_cap(struct map *_r_ m, enum err *_r_ out_err); enum err map_add_hashed_key(struct map *_r_ m, u64 *_r_ key, void *_r_ elem, enum err *_r_ out_err); enum err map_add(struct map *_r_ m, void *_r_ key, u64 key_size, void *_r_ elem, enum err *_r_ out_err); void *map_get(struct map *_r_ m, void *_r_ key, u64 key_size, enum err *_r_ out_err); enum err map_set_hashed_key(struct map *_r_ m, u64 *_r_ key, void *_r_ elem, enum err *_r_ out_err); enum err map_set(struct map *_r_ m, void *_r_ key, u64 key_size, void *_r_ elem, enum err *_r_ out_err); void *map_pop(struct map *_r_ m, void *_r_ key, u64 key_size, enum err *_r_ out_err); enum err map_destroy(struct map *_r_ m, enum err *_r_ out_err); u64 *map_default_hasher(void *key, u64 key_size); # if defined(IMP) || defined(IMP_MAP) struct map map_create(u64 elem_size, u64 cap, enum err *out_err) { struct map empty = {0}; struct map m = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); m._cap = cap; m._elem_size = elem_size; m._item_size = SIZEOF_MEMBER(struct map_item, key) + m._elem_size + 1; m._size_bytes = m._item_size * m._cap; m.data = malloc(m._size_bytes); if ( m.data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); goto err_exit; } memset(m.data, 0, m._size_bytes); m.indexs.cap = m._cap; m.indexs.data = malloc(sizeof(*m.indexs.data) * m.indexs.cap); if ( m.indexs.data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); goto err_exit; } memset(m.indexs.data, 0, sizeof(*m.indexs.data) * m.indexs.cap); m.keys.cap_bytes = m._cap; m.keys.data = malloc(sizeof(u64) * m.keys.cap_bytes); if ( m.keys.data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); goto err_exit; } memset(m.keys.data, 0, m.keys.cap_bytes); m.hash = map_default_hasher; LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return m; err_exit: if ( m.data != NULL ) free(m.data); if ( m.indexs.data != NULL ) free(m.indexs.data); if ( m.keys.data != NULL ) free(m.keys.data); return empty; } enum err map_inc_cap(struct map *_r_ m, enum err *_r_ out_err) { enum err err = ERR_OK; enum err *perr = &err; struct map old = {0}; struct map nm = {0}; u64 *index = 0; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m , out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m->data, out_err); if ( out_err != NULL ) { perr = out_err; } nm = map_create(m->_elem_size, (m->_cap * 2), perr); if ( *perr != ERR_OK ) { goto err_exit; } MAP_FOR_EACH_INDEXS(m, index) { struct map_item *mi = MAP_GET_INDEX(m, (*index)); map_add_hashed_key(&nm, mi->key, mi->item, perr); if ( *perr != ERR_OK ) { goto err_exit; } } old = *m; m->data = nm.data; m->size = nm.size; m->indexs = nm.indexs; m->keys = nm.keys; m->_cap = nm._cap; m->_size_bytes = nm._size_bytes; m->_item_size = nm._item_size; m->_elem_size = nm._elem_size; m->hash = nm.hash; map_destroy(&old, NULL); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; err_exit: map_destroy(&nm, NULL); return *perr; } enum err map_add_hashed_key(struct map *_r_ m, u64 *_r_ key, void *_r_ elem, enum err *_r_ out_err) { enum err err = ERR_OK; enum err *perr = &err; u64 i = 0; struct map_item *it = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m->data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(key, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(elem, out_err); if ( out_err != NULL ) { perr = out_err; } i = (key[0] + key[1] + key[2] + key[3]) % m->_cap; do { if ( i >= m->_cap ) { map_inc_cap(m, perr); if ( *perr != ERR_OK ) { return *perr; } } it = MAP_GET_INDEX(m, i++); } while (it->key[0] != 0 || it->key[1] != 0 || it->key[2] != 0 || it->key[3] != 0); /* printf("cap=%-5ld\telem_size=%-5ld\tsize_bytes=%-5ld\n", m->_cap, m->_elem_size, m->_size_bytes); */ memcpy(it->key, key, sizeof(u64) * 4); memcpy(it->item, elem, m->_elem_size); DA_APPEND(m->indexs, i-1, perr); if ( *perr != ERR_OK ) { memset(it->key, 0, sizeof(u64) * 4); memset(it->item, 0, m->_elem_size); return *perr; } *perr = ERR_OK; return ERR_OK; } enum err map_add(struct map *m, void *key, u64 key_size, void *elem, enum err *out_err) { enum err err = ERR_OK; enum err *perr = &err; struct key_bytes *sb = NULL; u64 *hash = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m->data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(key, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(elem, out_err); if ( out_err != NULL ) { perr = out_err; } hash = m->hash(key, key_size); if ( hash == NULL ) { *perr = ERR_FAILED_HASHING; return *perr; } map_add_hashed_key(m, hash, elem, perr); free(hash); if ( *perr != ERR_OK ) { return *perr; } sb = malloc(SIZEOF_MEMBER(struct key_bytes, size) + key_size); if ( sb == NULL ) { *perr = ERR_FAILED_ALLOC; return *perr; } memset(sb, 0, SIZEOF_MEMBER(struct key_bytes, size) + key_size); sb->size = key_size; memcpy(sb->key, key, key_size); DAV_APPEND( m->keys, sb, SIZEOF_MEMBER(struct key_bytes, size) + key_size, perr ); /* do { if (perr != ((void * ) 0)) { if ( * perr != ERR_OK) { break; } } if ((m -> keys).used_bytes + (sizeof(((struct key_bytes * ) 0) -> size) + key_size) >= (m -> keys).cap_bytes) { (m -> keys).cap_bytes *= 2; (m -> keys).data = realloc((m -> keys).data, (m -> keys).cap_bytes); if ((m -> keys).data == ((void * ) 0)) { if ((perr) != ((void * ) 0)) { *(perr) = ERR_FAILED_REALLOC; }; break; } } if ((m -> keys).data == ((void * ) 0)) { if ((m -> keys).cap_bytes == 0) { (m -> keys).cap_bytes = 32; (m -> keys).size = 0; (m -> keys).used_bytes = 0; }(m -> keys).data = malloc(sizeof(u64) * (m -> keys).cap_bytes); if ((m -> keys).data == ((void * ) 0)) { if ((perr) != ((void * ) 0)) { *(perr) = ERR_FAILED_ALLOC; }; break; } } memcpy(((u8 * )((m -> keys).data)) + (m -> keys).used_bytes, (sb), (sizeof(((struct key_bytes * ) 0) -> size) + key_size)); (m -> keys).used_bytes += (sizeof(((struct key_bytes * ) 0) -> size) + key_size); ++(m -> keys).size; if ((perr) != ((void * ) 0)) { *(perr) = ERR_OK; }; } while (0); */ free(sb); if ( *perr != ERR_OK ) { return *perr; } *perr = ERR_OK; return ERR_OK; } void * map_get(struct map *m, void *key, u64 key_size, enum err *out_err) { u64 i = 0; struct map_item *it = NULL; u64 *hash = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, NULL); LIB_ARG_MUST_NOT_BE_NULL(m , out_err, NULL); LIB_ARG_MUST_NOT_BE_NULL(m->data, out_err, NULL); LIB_ARG_MUST_NOT_BE_NULL(key , out_err, NULL); hash = m->hash(key, key_size); i = (hash[0] + hash[1] + hash[2] + hash[3]) % m->_cap; do { if ( i >= m->_cap ) { LIB_SET_IF_NOT_NULL(out_err, ERR_NOT_FOUND); free(hash); return NULL; } it = MAP_GET_INDEX(m, i++); } while (it->key[0] != hash[0] || it->key[1] != hash[1] || it->key[2] != hash[2] || it->key[3] != hash[3]); free(hash); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return it->item; } enum err map_set_hashed_key(struct map *_r_ m, u64 *_r_ key, void *_r_ elem, enum err *_r_ out_err) { enum err err = ERR_OK; enum err *perr = &err; u64 i = 0; struct map_item *it = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m->data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(key, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(elem, out_err); if ( out_err != NULL ) { perr = out_err; } i = (key[0] + key[1] + key[2] + key[3]) % m->_cap; do { if ( i >= m->_cap ) { *perr = ERR_NOT_FOUND; return *perr; } it = MAP_GET_INDEX(m, i++); } while (it->key[0] != key[0] || it->key[1] != key[1] || it->key[2] != key[2] || it->key[3] != key[3]); memcpy(it->item, elem, m->_elem_size); *perr = ERR_OK; return ERR_OK; } enum err map_set(struct map *_r_ m, void *_r_ key, u64 key_size, void *_r_ elem, enum err *_r_ out_err) { enum err err = ERR_OK; enum err *perr = &err; u64 *hash = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m->data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(key, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(elem, out_err); if ( out_err != NULL ) { perr = out_err; } hash = m->hash(key, key_size); if ( hash == NULL ) { *perr = ERR_FAILED_HASHING; return *perr; } map_set_hashed_key(m, hash, elem, perr); if ( *perr != ERR_OK ) { free(hash); return *perr; } free(hash); *perr = ERR_OK; return ERR_OK; } void *map_pop(struct map *m, void *key, u64 key_size, enum err *out_err); enum err map_destroy(struct map *m, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(m, out_err); if ( m->data != NULL ) free(m->data); if ( m->indexs.data != NULL ) free(m->indexs.data); if ( m->keys.data != NULL ) free(m->keys.data); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } u64 * map_default_hasher(void *key, u64 key_size) { u64 i = 0; u64 *k = NULL; k = malloc(sizeof(u64) * 4); if ( k == NULL ) { return NULL; } k[0] = 0; k[1] = 0; k[2] = 0; k[3] = 0; for ( i = 0; i < key_size; ++i ) { k[0] += ((u8*)key)[i] * 31; k[1] += ((u8*)key)[i] * 127; k[2] += ((u8*)key)[i] * 233; k[3] += ((u8*)key)[i] * 353; } return k; } # endif /* defined(IMP) || defined(IMP_MAP) */ # endif /* defined(WANT_MAP) || defined(WANT_ALL) */ /* ----------------------------- END MAP DEF ------------------------------- */ /* ---------------------------- START ENV DEF ------------------------------ */ # if defined(WANT_ENV) || defined(WANT_ALL) struct str getenv_as_str(const char *env, enum err *out_err); struct path getenv_as_path(const char *env, enum err *out_err); # endif /* defined(WANT_ENV) || defined(WANT_ALL) */ /* ----------------------------- END ENV DEF ------------------------------- */ /* ---------------------------- START PATH DEF ----------------------------- */ # if defined(WANT_PATH) || defined(WANT_ALL) # ifndef PATH_SIZE_LIMIT # define PATH_SIZE_LIMIT 1024 # endif /* PATH_SIZE_LIMIT */ struct path { char data[PATH_SIZE_LIMIT]; u64 size; }; struct path path_from_str(struct str str, enum err *out_err); struct path path_from_cstr(const char *cstr, u64 cstr_size, enum err *out_err); struct path path_from_cstr_ns(const char *cstr, enum err *out_err); struct path path_get_xdg_state_home(enum err *out_err); struct path path_get_xdg_data_home(enum err *out_err); struct path path_dirname(struct path path, enum err *out_err); struct path path_join(struct path lhs, struct path rhs, enum err *out_err); struct path path_join_with_str(struct path lhs, struct str rhs, enum err *out_err); struct path path_join_with_cstr(struct path lhs, const char *rhs, u64 rhs_size, enum err *out_err); struct path path_join_with_cstr_ns(struct path lhs, const char *rhs, enum err *out_err); bool path_exists(struct path path, int (*access)(const char *, int)); bool path_can_read(struct path path, int (*access)(const char *, int)); bool path_can_write(struct path path, int (*access)(const char *, int)); bool path_can_execute(struct path path, int (*access)(const char *, int)); bool path_mkdir(struct path path, u32 mode, bool do_create_parents, int (*mkdir)(const char *, u32), enum err *out_err); bool path_touch(struct path path, int (*open)(const char *, int), enum err *out_err); struct file { u8 *data; u64 size; }; struct file path_file_read_all(const struct path *path, enum err *out_err); enum err path_file_save(const struct path *path, const struct file *file, enum err *out_err); # endif /* defined(WANT_PATH) || defined(WANT_ALL) */ /* ----------------------------- END PATH DEF ------------------------------ */ /* ------------------------- START TOKENIZER DEF --------------------------- */ # if defined(WANT_TOKENIZER) || defined(WANT_ALL) struct tokenizer; struct tokenizer_options { bool (*skip_token)(struct tokenizer *tkn, char c); bool (*is_id)(struct tokenizer *tkn, char c); bool (*is_id_start)(struct tokenizer *tkn, char c); bool (*is_digit)(struct tokenizer *tkn, char c); bool (*is_num_lit)(struct tokenizer *tkn, struct str str); bool (*is_str_lit_start)(struct tokenizer *tkn, char c); bool (*is_str_lit_end)(struct tokenizer *tkn, char c); bool (*is_str_lit)(struct tokenizer *tkn, struct str str); }; enum tokenizer_loc_format { TLF_VIM = 0 }; enum token_type { TK_INVALID = -2, TK_EOF = -1, TK_NUL = '\0', TK_NL = '\n', TK_TAB = '\t', TK_SPACE = ' ', TK_ASTERISK = '*', TK_AMPERSAND = '&', TK_PLUS = '+', TK_MINUS = '-', TK_EQUAL = '=', TK_SLASH = '/', TK_BACKSLASH = '\\', TK_POUND = '#', TK_SEMICOLON = ';', TK_COLON = ':', TK_COMMA = ',', TK_DOT = '.', TK_UNDERSCORE = '_', TK_L_BRACES = '(', TK_R_BRACES = ')', TK_L_BRACKET = '[', TK_R_BRACKET = ']', TK_L_CUR_BRACES = '{', TK_R_CUR_BRACES = '}', TK_L_ANG_BRACKET = '<', TK_R_ANG_BRACKET = '>', TK_SINGLE_QUOTE = '\'', TK_DOUBLE_QUOTE = '"', TK_BACKTICK = '`', TK_TILDE = '~', TK_a = 'a', TK_b = 'b', TK_c = 'c', TK_d = 'd', TK_e = 'e', TK_f = 'f', TK_g = 'g', TK_h = 'h', TK_i = 'i', TK_j = 'j', TK_k = 'k', TK_l = 'l', TK_m = 'm', TK_n = 'n', TK_o = 'o', TK_p = 'p', TK_q = 'q', TK_r = 'r', TK_s = 's', TK_t = 't', TK_u = 'u', TK_v = 'v', TK_w = 'w', TK_x = 'x', TK_y = 'y', TK_z = 'z', TK_A = 'A', TK_B = 'B', TK_C = 'C', TK_D = 'D', TK_E = 'E', TK_F = 'F', TK_G = 'G', TK_H = 'H', TK_I = 'I', TK_J = 'J', TK_K = 'K', TK_L = 'L', TK_M = 'M', TK_N = 'N', TK_O = 'O', TK_P = 'P', TK_Q = 'Q', TK_R = 'R', TK_S = 'S', TK_T = 'T', TK_U = 'U', TK_V = 'V', TK_W = 'W', TK_X = 'X', TK_Y = 'Y', TK_Z = 'Z', TK_0 = '0', TK_1 = '1', TK_2 = '2', TK_3 = '3', TK_4 = '4', TK_5 = '5', TK_6 = '6', TK_7 = '7', TK_8 = '8', TK_9 = '9', TK_ID = 257, TK_NUM_LIT, TK_STR_LIT, TK_LAST = 512 }; struct token { enum token_type type; u64 loc_start; u64 loc_end; struct str string; void *extra; /* This is not used by the lib */ }; struct tokenizer { u64 i; struct tokenizer_options opts; struct token last; struct path src; struct str code; void *edata; /* This is not used by the lib */ }; struct tokenizer tokenizer_create(struct str code, struct path src, struct tokenizer_options *opts, enum err *out_err); /* In normal use this function does not fail! */ struct token tokenizer_next_token(struct tokenizer *tkn, enum err *out_err); enum token_type tokenizer_next_token_type(struct tokenizer *tkn, enum err *out_err); struct token tokenizer_peek_token(struct tokenizer *tkn, enum err *out_err); enum token_type tokenizer_peek_token_type(struct tokenizer *tkn, enum err *out_err); bool tokenizer_is_next(struct tokenizer *tkn, enum token_type type, struct token *out_tk, enum err *out_err); bool tokenizer_is_next_id(struct tokenizer *tkn, struct str string, struct token *out_tk, enum err *out_err); enum err tokenizer_destroy(struct tokenizer *tkn, enum err *out_err); const char *tokenizer_token_loc_temp(const struct tokenizer *tkn, const struct token *tk, enum tokenizer_loc_format format, enum err *out_err); const char *token_to_cstr(enum token_type type); struct tokenizer_options tokenizer_options_defaultlyzer( struct tokenizer_options *tkn_opts); bool tokenizer_skip_token(struct tokenizer *tkn, char c); bool tokenizer_is_id(struct tokenizer *tkn, char c); bool tokenizer_is_id_start(struct tokenizer *tkn, char c); bool tokenizer_is_digit(struct tokenizer *tkn, char c); bool tokenizer_is_num_lit(struct tokenizer *tkn, struct str str); bool tokenizer_is_str_lit_start(struct tokenizer *tkn, char c); bool tokenizer_is_str_lit_end(struct tokenizer *tkn, char c); bool tokenizer_is_str_lit(struct tokenizer *tkn, struct str str); # if defined(IMP) || defined(IMP_TOKENIZER) struct tokenizer tokenizer_create(struct str code, struct path src, struct tokenizer_options *opts, enum err *out_err) { struct tokenizer empty = {0}; struct tokenizer tkn = {0}; struct tokenizer_options defs = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); if ( opts == NULL ) { tkn.opts = defs; } else { tkn.opts = *opts; } tkn.opts = tokenizer_options_defaultlyzer(&tkn.opts); tkn.i = 0; tkn.code = code; tkn.src = src; return tkn; } struct token tokenizer_next_token(struct tokenizer *tkn, enum err *out_err) { static struct { char data[256]; u16 size; } buf = {0}; struct token empty = {0}; struct token tk = {0}; char c = 0; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); LIB_ARG_MUST_NOT_BE_NULL(tkn, out_err, empty); buf.size = 0; if ( tkn->i >= tkn->code.size ) { goto eof_tk; } c = tkn->code.data[tkn->i++]; while ( tkn->opts.skip_token(tkn, c) == true ) { c = tkn->code.data[tkn->i++]; } if ( tkn->opts.is_id_start(tkn, c) == true ) { tk.type = TK_ID; tk.loc_start = tkn->i-1; do { buf.data[buf.size++] = c; c = tkn->code.data[tkn->i++]; } while ( tkn->opts.is_id(tkn, c) == true ); --tkn->i; tk.string.data = buf.data; tk.string.size = buf.size; if ( tkn->opts.is_num_lit(tkn, tk.string) == true ) { tk.type = TK_NUM_LIT; } tk.loc_end = tkn->i-1; goto exit; } if ( tkn->opts.is_digit(tkn, c) == true ) { tk.type = TK_NUM_LIT; tk.loc_start = tkn->i-1; do { buf.data[buf.size++] = c; c = tkn->code.data[tkn->i++]; } while ( tkn->opts.is_digit(tkn, c) == true ); --tkn->i; tk.string.data = buf.data; tk.string.size = buf.size; tk.loc_end = tkn->i-1; goto exit; } if ( tkn->opts.is_str_lit_start(tkn, c) == true ) { tk.type = TK_STR_LIT; tk.loc_start = tkn->i-1; do { buf.data[buf.size++] = c; c = tkn->code.data[tkn->i++]; } while ( tkn->opts.is_str_lit_end(tkn, c) == false ); buf.data[buf.size++] = c; tk.string.data = buf.data; tk.string.size = buf.size - 1; tk.loc_end = tkn->i-1; goto exit; } tk.type = c; if ( tkn->i >= tkn->code.size ) { eof_tk: tk.type = TK_EOF; } tk.loc_start = tkn->i-1; tk.loc_end = tkn->i-1; exit: tkn->last = tk; return tk; } enum token_type tokenizer_next_token_type(struct tokenizer *tkn, enum err *out_err) { struct token tk = {0}; enum err err = ERR_OK; enum err *perr = &err; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, TK_INVALID); LIB_ARG_MUST_NOT_BE_NULL(tkn, out_err, TK_INVALID); if ( out_err != NULL ) { perr = out_err; } tk = tokenizer_next_token(tkn, perr); if ( *perr != ERR_OK ) { return TK_INVALID; } LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return tk.type; } struct token tokenizer_peek_token(struct tokenizer *tkn, enum err *out_err) { enum err err = ERR_OK; enum err *perr = &err; u64 last_i = 0; struct token empty = {0}; struct token tk = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); LIB_ARG_MUST_NOT_BE_NULL(tkn, out_err, empty); if ( out_err != NULL ) { perr = out_err; } last_i = tkn->i; tk = tokenizer_next_token(tkn, perr); tkn->i = last_i; return tk; } enum token_type tokenizer_peek_token_type(struct tokenizer *tkn, enum err *out_err) { enum err err = ERR_OK; enum err *perr = &err; struct token tk = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, TK_INVALID); LIB_ARG_MUST_NOT_BE_NULL(tkn, out_err, TK_INVALID); tk = tokenizer_peek_token(tkn, perr); return tk.type; } bool tokenizer_is_next(struct tokenizer *tkn, enum token_type type, struct token *out_tk, enum err *out_err) { enum err err = ERR_OK; struct token tk = {0}; u64 pi = 0; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, false); LIB_ARG_MUST_NOT_BE_NULL(tkn, out_err, false); pi = tkn->i; tk = tokenizer_next_token(tkn, &err); if ( tk.type != type ) { tkn->i = pi; return false; } LIB_SET_IF_NOT_NULL(out_tk, tk); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return true; } bool tokenizer_is_next_id(struct tokenizer *tkn, struct str string, struct token *out_tk, enum err *out_err) { enum err err = ERR_OK; struct token tk = {0}; u64 pi = 0; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, false); LIB_ARG_MUST_NOT_BE_NULL(tkn, out_err, false); LIB_STR_MUST_NOT_BE_EMPTY(string, out_err, false); pi = tkn->i; tk = tokenizer_next_token(tkn, &err); if ( tk.type != TK_ID ) { tkn->i = pi; return false; } if ( str_eq_str(tk.string, string) == false ) { tkn->i = pi; return false; } LIB_SET_IF_NOT_NULL(out_tk, tk); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return true; } enum err tokenizer_destroy(struct tokenizer *tkn, enum err *out_err); const char * tokenizer_token_loc_temp(const struct tokenizer *tkn, const struct token *tk, enum tokenizer_loc_format format, enum err *out_err) { static struct { char data[1024]; u64 size; } buf = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, NULL); LIB_ARG_MUST_NOT_BE_NULL(tkn, out_err, NULL); LIB_ARG_MUST_NOT_BE_NULL(tk, out_err, NULL); buf.size = 0; switch ( format ) { case TLF_VIM: { u64 col = 0; memcpy(buf.data, tkn->src.data, tkn->src.size); buf.size += tkn->src.size; buf.data[buf.size++] = ':'; { u64 i = 0; u64 line = 0; struct str line_str = {0}; for ( i = 0; i < tk->loc_start; ++i ) { line += ( tkn->code.data[i] == '\n' ); } line_str = str_from_i64_temp((i64)line); memcpy(buf.data + buf.size, line_str.data, line_str.size); buf.size += line_str.size; /* Col values wrong */ while ( tkn->code.data[i] != '\n' && i > 0 ) { --i; } col = tk->loc_start - i; } buf.data[buf.size++] = ':'; { struct str col_str = {0}; col_str = str_from_i64_temp((i64)col); memcpy(buf.data + buf.size, col_str.data, col_str.size); buf.size += col_str.size; } buf.data[buf.size++] = ':'; buf.data[buf.size++] = 0; } break; default: LIB_SET_IF_NOT_NULL(out_err, ERR_INVALID_ARG); return NULL; } LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return buf.data; } const char * token_to_cstr(enum token_type type) { switch ( type ) { case TK_INVALID: return "TK_INVALID"; case TK_EOF: return "TK_EOF"; case TK_NUL: return "TK_NUL"; case TK_NL: return "TK_NL"; case TK_TAB: return "TK_TAB"; case TK_SPACE: return "TK_SPACE"; case TK_ASTERISK: return "TK_ASTERISK"; case TK_AMPERSAND: return "TK_AMPERSAND"; case TK_PLUS: return "TK_PLUS"; case TK_MINUS: return "TK_MINUS"; case TK_EQUAL: return "TK_EQUAL"; case TK_SLASH: return "TK_SLASH"; case TK_BACKSLASH: return "TK_BACKSLASH"; case TK_POUND: return "TK_POUND"; case TK_SEMICOLON: return "TK_SEMICOLON"; case TK_COLON: return "TK_COLON"; case TK_COMMA: return "TK_COMMA"; case TK_DOT: return "TK_DOT"; case TK_UNDERSCORE: return "TK_UNDERSCORE"; case TK_L_BRACES: return "TK_L_BRACES"; case TK_R_BRACES: return "TK_R_BRACES"; case TK_L_BRACKET: return "TK_L_BRACKET"; case TK_R_BRACKET: return "TK_R_BRACKET"; case TK_L_CUR_BRACES: return "TK_L_CUR_BRACES"; case TK_R_CUR_BRACES: return "TK_R_CUR_BRACES"; case TK_L_ANG_BRACKET: return "TK_L_ANG_BRACKET"; case TK_R_ANG_BRACKET: return "TK_R_ANG_BRACKET"; case TK_SINGLE_QUOTE: return "TK_SINGLE_QUOTE"; case TK_DOUBLE_QUOTE: return "TK_DOUBLE_QUOTE"; case TK_BACKTICK: return "TK_BACKTICK"; case TK_TILDE: return "TK_TILDE"; case TK_a: return "TK_a"; case TK_b: return "TK_b"; case TK_c: return "TK_c"; case TK_d: return "TK_d"; case TK_e: return "TK_e"; case TK_f: return "TK_f"; case TK_g: return "TK_g"; case TK_h: return "TK_h"; case TK_i: return "TK_i"; case TK_j: return "TK_j"; case TK_k: return "TK_k"; case TK_l: return "TK_l"; case TK_m: return "TK_m"; case TK_n: return "TK_n"; case TK_o: return "TK_o"; case TK_p: return "TK_p"; case TK_q: return "TK_q"; case TK_r: return "TK_r"; case TK_s: return "TK_s"; case TK_t: return "TK_t"; case TK_u: return "TK_u"; case TK_v: return "TK_v"; case TK_w: return "TK_w"; case TK_x: return "TK_x"; case TK_y: return "TK_y"; case TK_z: return "TK_z"; case TK_A: return "TK_A"; case TK_B: return "TK_B"; case TK_C: return "TK_C"; case TK_D: return "TK_D"; case TK_E: return "TK_E"; case TK_F: return "TK_F"; case TK_G: return "TK_G"; case TK_H: return "TK_H"; case TK_I: return "TK_I"; case TK_J: return "TK_J"; case TK_K: return "TK_K"; case TK_L: return "TK_L"; case TK_M: return "TK_M"; case TK_N: return "TK_N"; case TK_O: return "TK_O"; case TK_P: return "TK_P"; case TK_Q: return "TK_Q"; case TK_R: return "TK_R"; case TK_S: return "TK_S"; case TK_T: return "TK_T"; case TK_U: return "TK_U"; case TK_V: return "TK_V"; case TK_W: return "TK_W"; case TK_X: return "TK_X"; case TK_Y: return "TK_Y"; case TK_Z: return "TK_Z"; case TK_0: return "TK_0"; case TK_1: return "TK_1"; case TK_2: return "TK_2"; case TK_3: return "TK_3"; case TK_4: return "TK_4"; case TK_5: return "TK_5"; case TK_6: return "TK_6"; case TK_7: return "TK_7"; case TK_8: return "TK_8"; case TK_9: return "TK_9"; case TK_ID: return "TK_ID"; case TK_NUM_LIT: return "TK_NUM_LIT"; case TK_STR_LIT: return "TK_STR_LIT"; default: return "TK_UNKNOWN"; } return "TK_UNKNOWN"; } struct tokenizer_options tokenizer_options_defaultlyzer(struct tokenizer_options *tkn_opts) { struct tokenizer_options defs = {0}; if ( tkn_opts != NULL ) { defs = *tkn_opts; } LIB_SET_IF_NULL(defs.skip_token, tokenizer_skip_token); LIB_SET_IF_NULL(defs.is_id, tokenizer_is_id); LIB_SET_IF_NULL(defs.is_id_start, tokenizer_is_id_start); LIB_SET_IF_NULL(defs.is_digit, tokenizer_is_digit); LIB_SET_IF_NULL(defs.is_num_lit, tokenizer_is_num_lit); LIB_SET_IF_NULL(defs.is_str_lit_start, tokenizer_is_str_lit_start); LIB_SET_IF_NULL(defs.is_str_lit_end, tokenizer_is_str_lit_end); LIB_SET_IF_NULL(defs.is_str_lit, tokenizer_is_str_lit); LIB_SET_IF_NULL(defs.skip_token, tokenizer_skip_token); return defs; } bool tokenizer_skip_token(struct tokenizer *tkn, char c) { UNUSED(tkn); return (c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'); } bool tokenizer_is_id(struct tokenizer *tkn, char c) { UNUSED(tkn); return (c == '_') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); } bool tokenizer_is_id_start(struct tokenizer *tkn, char c) { UNUSED(tkn); return tokenizer_is_id(tkn, c); } bool tokenizer_is_digit(struct tokenizer *tkn, char c) { UNUSED(tkn); return (c >= '0' && c <= '9'); } bool tokenizer_is_num_lit(struct tokenizer *tkn, struct str str) { u64 i = 0; UNUSED(tkn); for ( i = 0; i < str.size; ++i ) { if ( ! tokenizer_is_digit(tkn, str.data[i]) ) { return false; } } return true; } bool tokenizer_is_str_lit_start(struct tokenizer *tkn, char c) { UNUSED(tkn); return (c == '\'' || c == '"'); } bool tokenizer_is_str_lit_end(struct tokenizer *tkn, char c) { return tokenizer_is_str_lit_start(tkn, c); } bool tokenizer_is_str_lit(struct tokenizer *tkn, struct str str) { UNUSED(tkn); UNUSED(str); return true; } # endif /* defined(IMP) || defined(IMP_TOKENIZER) */ # endif /* defined(WANT_TOKENIZER) || defined(WANT_ALL) */ /* -------------------------- END TOKENIZER DEF ---------------------------- */ /* ---------------------------- START CMD DEF ------------------------------ */ # if defined(WANT_CMD) || defined(WANT_ALL) struct cmd { char *exe; struct { char **data; u64 size; u64 cap; } args; }; # define cmd_create_ns(Exe, OutErr) \ cmd_create( \ (struct str) { \ .data=(Exe), \ .size=cstr_len_max((Exe), STR_SIZE_LIMIT, NULL, (OutErr)) \ }, \ (OutErr) \ ) struct cmd cmd_create(struct str exe, enum err *_r_ out_err); # define cmd_set_exe_ns(Cmd, Exe, OutErr) \ cmd_set_exe( \ (Cmd), \ (struct str) { \ .data=(Exe), \ .size=cstr_len_max((Exe), STR_SIZE_LIMIT, NULL, (OutErr)) \ }, \ (OutErr) \ ) enum err cmd_set_exe(struct cmd *_r_ cmd, struct str exe, enum err *_r_ out_err); # define cmd_append_arg_ns(Cmd, Arg, OutErr) \ cmd_append_arg( \ (Cmd), \ (struct str) { \ .data=(Arg), \ .size=cstr_len_max((Arg), STR_SIZE_LIMIT, NULL, (OutErr)) \ }, \ (OutErr) \ ) enum err cmd_append_arg(struct cmd *_r_ cmd, struct str arg, enum err *_r_ out_err); enum err cmd_exec(struct cmd *_r_ cmd, enum err *_r_ out_err); enum err cmd_destroy(struct cmd *cmd, enum err *out_err); # if defined(IMP_CMD) || defined(IMP) struct cmd cmd_create(struct str exe, enum err *_r_ out_err) { struct cmd empty = {0}; struct cmd cmd = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); LIB_ARG_MUST_NOT_BE_NULL(exe.data, out_err, empty); cmd.exe = malloc(exe.size+1); if ( cmd.exe == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); goto exit_err; } cmd.exe[exe.size] = 0; memcpy(cmd.exe, exe.data, exe.size); cmd.args.cap = 32; cmd.args.data = malloc(sizeof(*cmd.args.data) * cmd.args.cap); if ( cmd.args.data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); goto exit_err; } DA_APPEND(cmd.args, cmd.exe, out_err); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return cmd; exit_err: LIB_FREE(cmd.exe); LIB_FREE(cmd.args.data); return (struct cmd){0}; } enum err cmd_set_exe(struct cmd *_r_ cmd, struct str exe, enum err *_r_ out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(exe.data, out_err); if ( cmd->exe != NULL ) { LIB_FREE(cmd->exe); } cmd->exe = malloc(exe.size+1); if ( cmd->exe == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); return ERR_FAILED_ALLOC; } cmd->exe[exe.size] = 0; memcpy(cmd->exe, exe.data, exe.size); cmd->args.data[0] = cmd->exe; LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } enum err cmd_append_arg(struct cmd *_r_ cmd, struct str arg, enum err *_r_ out_err) { enum err err = ERR_OK; enum err *perr = &err; char *t = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->args.data, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(arg.data, out_err); if ( out_err != NULL ) { perr = out_err; } t = malloc(arg.size + 1); if ( t == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); return ERR_FAILED_ALLOC; } t[arg.size] = 0; memcpy(t, arg.data, arg.size); DA_APPEND(cmd->args, t, perr); return *perr; } enum err cmd_exec(struct cmd *_r_ cmd, enum err *_r_ out_err) { i32 pid = -1; i32 status = 0; LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->exe, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->args.data, out_err); cmd->args.data[cmd->args.size] = NULL; pid = fork(); if ( pid < 0 ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_FORK); return ERR_FAILED_FORK; } if ( pid == 0 ) { /* printf("exe=`%s`\n", cmd->exe); DA_FOREACH(cmd->args, it) { printf("arg=`%s`\n", *it); } */ execve(cmd->exe, cmd->args.data, NULL); exit(1); } if ( waitpid(pid, &status, 0) < 0 ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_WAITPID); return ERR_FAILED_WAITPID; } if ( WIFEXITED(status) == true ) { if ( WEXITSTATUS(status) != 0 ) { LIB_SET_IF_NOT_NULL(out_err, ERR_CMD_NON_ZERO_EXIT_CODE); return ERR_CMD_NON_ZERO_EXIT_CODE; } } LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } enum err cmd_destroy(struct cmd *cmd, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->exe, out_err); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(cmd->args.data, out_err); LIB_FREE(cmd->exe); DA_FOREACH(cmd->args, it) { if ( *it == cmd->exe ) continue; LIB_FREE(*it); } LIB_FREE(cmd->args.data); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } # endif /* defined(IMP_CMD) || defined(IMP) */ # endif /* defined(WANT_CMD) || defined(WANT_ALL) */ /* ----------------------------- END CMD DEF ------------------------------- */ /* ---------------------------- START SGFX DEF ----------------------------- */ # if defined(WANT_SGFX) || defined(WANT_ALL) # ifndef SGFX_WIDTH # define SGFX_WIDTH 800 # endif /* SGFX_WIDTH */ # ifndef SGFX_HEIGHT # define SGFX_HEIGHT 600 # endif /* SGFX_HEIGHT */ # define SGFX_WIDTH_CSTR MACRO_STR_VALUE_X(SGFX_WIDTH) # define SGFX_HEIGHT_CSTR MACRO_STR_VALUE_X(SGFX_HEIGHT) struct sgfx_rgb { u8 r, g, b; }; struct sgfx_rgba { u8 r, g, b, a; }; struct sgfx_canvas { u32 pixels[SGFX_WIDTH * SGFX_HEIGHT]; u64 width; u64 height; u64 cap; }; enum err sgfx_canvas_populate(struct sgfx_canvas *canvas, enum err *out_err); enum err sgfx_canvas_fill(struct sgfx_canvas *canvas, u32 color, enum err *out_err); enum err sgfx_canvas_fill_rect(struct sgfx_canvas *canvas, struct u64vec2 pos, struct u64vec2s size, u32 color, enum err *out_err); enum err sgfx_canvas_save_to_ppm(const struct sgfx_canvas *canvas, struct path path, enum err *out_err); # endif /* defined(WANT_SGFX) || defined(WANT_ALL) */ /* ----------------------------- END SGFX DEF ------------------------------ */ /* --------------------------- START RAYLIB DEF ---------------------------- */ # if defined(WANT_RAYLIB) || defined(WANT_ALL) # if defined(RAYLIB_H) enum err raylib_draw_str(const struct str_builder *str, Font font, Vector2 position, float fontSize, float spacing, Color tint, enum err *out_err); # endif /* defined(RAYLIB_H) */ # endif /* defined(WANT_RAYLIB) || defined(WANT_ALL) */ /* ---------------------------- END RAYLIB DEF ----------------------------- */ /* ---------------------------- START GUI DEF ------------------------------ */ # if defined(WANT_GUI) || defined(WANT_ALL) enum gui_unit_type { GUT_ABSOLUTE = 0, GUT_PERCENTAGE }; enum gui_unit_reference { GUR_TOP_LEFT = 0, GUR_CENTER }; struct gui_unit { enum gui_unit_type type; enum gui_unit_reference ref; i64 value; }; enum gui_item_type { GIT_BUTTOM = 0 }; struct gui_item { enum gui_item_type type; struct gui_unit x; struct gui_unit y; struct gui_unit width; struct gui_unit height; }; struct gui { struct { struct gui_item *data; u64 size; u64 cap; } items; }; struct gui gui_open_window(const char *title, enum err *out_err); bool gui_should_close(struct gui *gui, enum err *out_err); enum err gui_start_loop(struct gui *gui, enum err *out_err); enum err gui_add_buttom(struct gui *gui, struct gui_unit x, struct gui_unit y, struct gui_unit width, struct gui_unit height, enum err *out_err); enum err gui_end_loop(struct gui *gui, enum err *out_err); enum err gui_close_window(struct gui *gui, enum err *out_err); # if defined(IMP) || defined(IMP_STR) struct gui gui_open_window(const char *title, enum err *out_err) { struct gui empty = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); LIB_ARG_MUST_NOT_BE_NULL(title, out_err, empty); # if defined(RAYLIB_H) InitWindow(800, 600, title); SetWindowState(FLAG_WINDOW_RESIZABLE); # endif /* defined(RAYLIB_H) */ LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return empty; } bool gui_should_close(struct gui *gui, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, true); LIB_ARG_MUST_NOT_BE_NULL(gui, out_err, true); (void) gui; # if defined(RAYLIB_H) LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return WindowShouldClose(); # endif /* defined(RAYLIB_H) */ LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return true; } enum err gui_start_loop(struct gui *gui, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(gui, out_err); # if defined(RAYLIB_H) BeginDrawing(); # endif /* defined(RAYLIB_H) */ LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } enum err gui_add_buttom(struct gui *gui, struct gui_unit x, struct gui_unit y, struct gui_unit width, struct gui_unit height, enum err *out_err) { # if defined(RAYLIB_H) Color red = { 230, 41, 55, 255 }; # endif /* defined(RAYLIB_H) */ LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(gui, out_err); # if defined(RAYLIB_H) DrawRectangle((i32)x.value, (i32)y.value, (i32)width.value, (i32)height.value, red); # endif /* defined(RAYLIB_H) */ LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } enum err gui_end_loop(struct gui *gui, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(gui, out_err); # if defined(RAYLIB_H) EndDrawing(); # endif /* defined(RAYLIB_H) */ LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } enum err gui_close_window(struct gui *gui, enum err *out_err) { LIB_ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); LIB_ARG_MUST_NOT_BE_NULL_SET_RET_ERR(gui, out_err); # if defined(RAYLIB_H) CloseWindow(); # endif /* defined(RAYLIB_H) */ LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } # endif /* defined(IMP) || defined(IMP_STR) */ # endif /* defined(WANT_GUI) || defined(WANT_ALL) */ /* ----------------------------- END GUI DEF ------------------------------- */ /* ---------------------------- START SLOP DEF ----------------------------- */ # if defined(WANT_SLOP) || defined(WANT_ALL) u8 *slop_file_slurp(const char *_r_ path, u64 *_r_ out_size, enum err *_r_ out_err); enum err slop_file_save(const char *_r_ path, u8 *_r_ data, u64 size, enum err *_r_ out_err); # if defined(IMP) || defined(IMP_SLOP) u8 * slop_file_slurp(const char *_r_ path, u64 *_r_ out_size, enum err *_r_ out_err) { enum err err = ERR_OK; enum err *perr = &err; struct path p = {0}; struct file f = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, NULL); LIB_ARG_MUST_NOT_BE_NULL(path, out_err, NULL); if ( out_err != NULL ) { perr = out_err; } p = path_from_cstr_ns(path, perr); f = path_file_read_all(&p, perr); if ( out_size != NULL ) { *out_size = f.size; } return f.data; } enum err slop_file_save(const char *_r_ path, u8 *_r_ data, u64 size, enum err *_r_ out_err); # endif /* defined(IMP) || defined(IMP_SLOP) */ # endif /* defined(WANT_SLOP) || defined(WANT_ALL) */ /* ----------------------------- END SLOP DEF ------------------------------ */ # if defined(IMP) || defined(IMP_STR) # define _SET_IF_NOT_NULL(var, err) \ if ( var != NULL ) { \ *var = err; \ } # define _ARG_IF_NOT_NULL_MUST_BE(arg, val, ret_val) \ if ( arg != NULL ) { \ if ( *arg != val ) { \ return ret_val; \ } \ } # define _ARG_IF_NOT_NULL_MUST_BE_RET_IT(arg, val) \ if ( arg != NULL ) { \ if ( *arg != val ) { \ return *arg; \ } \ } # define _ARG_MUST_NOT_BE_NULL_RET_ERR(arg) \ if ( (arg) == NULL ) { \ return ERR_NULL_ARG; \ } # define _ARG_MUST_NOT_BE_NULL(arg, err_var, ret_val) \ if ( (arg) == NULL ) { \ _SET_IF_NOT_NULL(err_var, ERR_NULL_ARG); \ return ret_val; \ } # define _ARG_MUST_NOT_BE_NULL_SET_RET_ERR(arg, err_var) \ if ( (arg) == NULL ) { \ _SET_IF_NOT_NULL(err_var, ERR_NULL_ARG); \ return ERR_NULL_ARG; \ } # ifndef _CTYPE_H # define LIB_H_CTYPE # define isspace(c) ((c) == ' ' || (c) == '\f' \ || (c) == '\n' || (c) == '\r' \ || (c) == '\t' || (c) == '\v') # define isdigit(c) ((c) >= '0' && (c) <= '9') # endif /* _CTYPE_H */ # ifndef _STRING_H # define LIB_H_STRING void *_str_memcpy(void *dest, const void *src, u64 n); void * _str_memcpy(void *dest, const void *src, u64 n) { u64 i = 0; char *_dest = (char *) dest; char *_src = (char *) src; for ( i = 0; i < n; ++i ) { _dest[i] = _src[i]; } return dest; } # define memcpy _str_memcpy # endif /* _STRING_H */ /* ----------------------------- START LIB IMP ----------------------------- */ /* ------------------------------ END LIB IMP ------------------------------ */ /* ---------------------------- START CSTR IMP ----------------------------- */ # if defined(WANT_CSTR) || defined(WANT_ALL) u64 cstr_len_max(const char *cstr, u64 max, bool *out_hit_max, enum err *out_err) { u64 ret = 0; _ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, 0); if ( cstr == NULL ) { _SET_IF_NOT_NULL(out_err, ERR_NULL_ARG); return 0; } _loop: if ( ret >= max ) { _SET_IF_NOT_NULL(out_hit_max, true); goto _loop_end; } if ( cstr[ret] == '\0' ) { goto _loop_end; } ++ret; goto _loop; _loop_end: _SET_IF_NOT_NULL(out_err, ERR_OK); return ret; } # endif /* defined(WANT_CSTR) || defined(WANT_ALL) */ /* ----------------------------- END CSTR IMP ------------------------------ */ /* ---------------------------- START STR DEF ------------------------------ */ # if defined(WANT_STR) || defined(WANT_ALL) struct str str_from_cstr(const char *cstr, u64 cstr_size, enum err *out_err) { struct str empty = {0}; struct str str = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); if ( cstr == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_NULL_ARG); return empty; } if ( cstr_size >= STR_SIZE_LIMIT ) { LIB_SET_IF_NOT_NULL(out_err, ERR_TOO_BIG); return empty; } str.data = cstr; str.size = cstr_size; _SET_IF_NOT_NULL(out_err, ERR_OK); return str; } struct str str_from_cstr_ns(const char *cstr, enum err *out_err) { struct str empty = {0}; struct str str = {0}; bool too_big = false; enum err err = ERR_OK; if ( cstr == NULL ) { _SET_IF_NOT_NULL(out_err, ERR_NULL_ARG); return empty; } str.size = cstr_len_max(cstr, STR_SIZE_LIMIT, &too_big, &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return empty; } if ( too_big ) { _SET_IF_NOT_NULL(out_err, ERR_TOO_BIG); return empty; } str.data = cstr; _SET_IF_NOT_NULL(out_err, ERR_OK); return str; } struct str str_from_i64(i64 num, enum err *out_err) { struct str empty = {0}; struct str str_temp = {0}; struct str ret = {0}; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); str_temp = str_from_i64_temp(num); ret.size = str_temp.size; ret.should_be_freed = true; ret.data = malloc(str_temp.size); if ( ret.data == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); return empty; } memcpy((void *)ret.data, str_temp.data, str_temp.size); LIB_SET_IF_NOT_NULL(out_err, ERR_OK); return ret; } struct str str_from_i64_temp(i64 num) { static char buffer[32]; struct { char data[24]; u8 size; } buf = {0}; u64 _num = 0; struct str ret = {0}; ret.data = buffer; if ( num < 0 ) { buf.data[buf.size++] = '-'; num *= -1; } _num = (u64)num; while ( 1 ) { u8 mod = (u8) (_num % 10); buf.data[buf.size++] = (char) (mod + 48); _num /= 10; if ( buf.size >= 24 ) { _loop: buffer[ret.size++] = buf.data[--buf.size]; if ( buf.size > 0 ) { goto _loop; } } if ( _num == 0 ) { break; } } if ( buf.size == 0 ) { goto exit; } _out_loop: buffer[ret.size++] = buf.data[--buf.size]; if ( buf.size > 0 ) { goto _out_loop; } exit: buffer[ret.size] = 0; return ret; } struct str str_dup(struct str str) { struct str ret = str; ret.data = malloc(ret.size * sizeof(*ret.data)); memcpy((char *)ret.data, str.data, str.size); ret.should_be_freed = true; return ret; } intmax_t str_to_int(struct str str, enum err *out_err) { intmax_t res = 0; u64 i = 0; bool negative = false; int digits[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 }; if ( ! str_is_int(str) ) { _SET_IF_NOT_NULL(out_err, ERR_NOT_INT); return -1; } if ( str.size > STR_SIZE_LIMIT ) { _SET_IF_NOT_NULL(out_err, ERR_TOO_BIG); return -1; } negative = (str.data[0] == '-'); if ( str.data[0] == '-' || str.data[0] == '+' ) { ++str.data; --str.size; } for ( i = 0; i < str.size; ++i ) { intmax_t digit = digits[(str.size - (i + 1))]; res += (str.data[i] - 48) * digit; } if ( negative == true ) { res *= -1; } _SET_IF_NOT_NULL(out_err, ERR_OK); return res; } struct str str_rstrip(struct str str) { while ( isspace(str.data[str.size-1]) ) { --str.size; } return str; } struct str str_lstrip(struct str str) { while ( isspace(*str.data) ) { ++str.data; --str.size; } return str; } struct str str_strip(struct str str) { return str_lstrip(str_rstrip(str)); } u64 str_lindex(struct str str, char c) { u64 i = 0; for ( ; i < str.size; ++i ) { if ( str.data[i] == c ) { return i; } } return (u64) -1; } u64 str_rindex(struct str str, char c) { u64 i = str.size - 1; for ( ; i > 0; --i ) { if ( str.data[i] == c ) { return i; } } if ( str.data[i] == c ) { return i; } return (u64) -1; } struct str_tokenizer str_tokenize(struct str str, char c) { struct str_tokenizer st = {0}; st.str = str; st.c = c; return st; } struct str_tokenizer str_tokenize_func(struct str str, bool (*f)(char c)) { struct str_tokenizer st = {0}; st.str = str; st.f = f; return st; } struct str str_tokenizer_next(struct str_tokenizer *st) { struct str str; if ( st == NULL ) { goto ret_err; } if ( st->cur >= st->str.size ) { goto ret_done; } if ( st->str.data[st->cur] == '\0' ) { goto ret_done; } str = st->str; str.data += st->cur; str.size = 0; if ( st->f != NULL ) { while ( (! st->f(str.data[str.size])) && st->cur < st->str.size ) { ++str.size; ++st->cur; } } else { while ( str.data[str.size] != st->c && st->cur < st->str.size ) { ++str.size; ++st->cur; } } ++st->cur; if ( str.size == 0 ) { goto ret_empty; } return str; ret_empty: str.data = ""; str.size = 0; return str; ret_done: str.data = ""; str.size = (u64) -1; return str; ret_err: str.data = ""; str.size = (u64) -2; return str; } struct str str_slice(struct str str, u64 from, u64 to) { if ( from > str.size ) { goto ret_err; } if ( from > to ) { goto ret_err; } to = ( to > str.size ) * str.size \ + ( to <= str.size ) * to; str.data += from; str.size = to - from; return str; ret_err: str.data = ""; str.size = (u64) -2; return str; } bool str_eq_cstr(struct str str, const char *cstr, u64 cstr_size) { u64 i = 0; if ( str.size != cstr_size ) { return false; } for ( i = 0; i < str.size; ++i ) { if ( str.data[i] != cstr[i] ) { return false; } } return true; } bool str_eq_str(struct str str1, struct str str2) { u64 i = 0; if ( str1.size != str2.size ) { return false; } for ( i = 0; i < str1.size; ++i ) { if ( str1.data[i] != str2.data[i] ) { return false; } } return true; } bool str_startswith_cstr(struct str str, const char *cstr, u64 cstr_size) { u64 i = 0; if ( cstr_size > str.size ) { return false; } for ( i = 0; i < cstr_size; ++i ) { if ( str.data[i] != cstr[i] ) { return false; } } return true; } bool str_is_int(struct str str) { u64 i = 0; if ( str.size == 0 ) { return false; } if ( str.size == 1 ) { return isdigit(str.data[0]); } i += (str.data[0] == '-' || str.data[0] == '+'); for ( ; i < str.size; ++i ) { if ( ! isdigit(str.data[i]) ) { return false; } } return true; } struct str str_builder_to_str(const struct str_builder *str_bldr) { struct str str = {0}; str.data = str_bldr->data; str.size = str_bldr->size; str.should_be_freed = true; return str; } # endif /* defined(WANT_STR) || defined(WANT_ALL) */ /* ----------------------------- END STR IMP ------------------------------- */ /* ---------------------------- START ENV IMP ------------------------------ */ # if defined(WANT_ENV) || defined(WANT_ALL) struct str getenv_as_str(const char *name, enum err *out_err) { struct str empty = {0}; struct str str = {0}; char *res = NULL; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); LIB_ARG_MUST_NOT_BE_NULL(name, out_err, empty); res = getenv(name); if ( res == NULL ) { LIB_SET_IF_NOT_NULL(out_err, ERR_NOT_FOUND); return str; } return str_from_cstr_ns(res, out_err); } struct path getenv_as_path(const char *name, enum err *out_err) { struct path empty = {0}; struct str str = {0}; enum err err; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); LIB_ARG_MUST_NOT_BE_NULL(name, out_err, empty); str = getenv_as_str(name, &err); if ( err ) { LIB_SET_IF_NOT_NULL(out_err, err); return empty; } return path_from_str(str, out_err); } # endif /* defined(WANT_ENV) || defined(WANT_ALL) */ /* ----------------------------- END ENV IMP ------------------------------- */ /* ---------------------------- START PATH IMP ----------------------------- */ # if defined(WANT_PATH) || defined(WANT_ALL) struct path path_from_str(struct str str, enum err *out_err) { struct path path = {0}; if ( str.size > PATH_SIZE_LIMIT ) { _SET_IF_NOT_NULL(out_err, ERR_TOO_BIG); return path; } memcpy(path.data, str.data, str.size); path.size = str.size; _SET_IF_NOT_NULL(out_err, ERR_OK); return path; } struct path path_from_cstr(const char *cstr, u64 cstr_size, enum err *out_err) { enum err err; struct str str; struct path path = {0}; str = str_from_cstr(cstr, cstr_size, &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return path; } return path_from_str(str, out_err); } struct path path_from_cstr_ns(const char *cstr, enum err *out_err) { enum err err; struct str str; struct path path = {0}; _ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, path); str = str_from_cstr_ns(cstr, &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return path; } return path_from_str(str, out_err); } struct path path_get_xdg_state_home(enum err *out_err) { struct path empty = {0}; struct path path = {0}; enum err err; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); path = getenv_as_path("XDG_STATE_HOME", &err); if ( err == ERR_NOT_FOUND ) { path = getenv_as_path("HOME", &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return empty; } path = path_join_with_cstr(path, ".local/state", 12, NULL); } else if ( err ) { _SET_IF_NOT_NULL(out_err, err); return empty; } _SET_IF_NOT_NULL(out_err, ERR_OK); return path; } struct path path_get_xdg_data_home(enum err *out_err) { struct path empty = {0}; struct path path = {0}; enum err err; LIB_ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); path = getenv_as_path("XDG_DATA_HOME", &err); if ( err == ERR_NOT_FOUND ) { path = getenv_as_path("HOME", &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return empty; } path = path_join_with_cstr(path, ".local/share", 12, NULL); } else if ( err ) { _SET_IF_NOT_NULL(out_err, err); return empty; } _SET_IF_NOT_NULL(out_err, ERR_OK); return path; } struct path path_dirname(struct path path, enum err *out_err) { struct path empty = {0}; struct path ret = {0}; u64 i = 0; if ( path.size == 0 || path.data[0] == 0 ) { _SET_IF_NOT_NULL(out_err, ERR_PATH_EMPTY); return empty; } i = path.size; loop: --i; if ( path.data[i] == '/' ) { goto exit_loop; } if ( i == 0 ) { ret.data[0] = '.'; ret.data[1] = 0; ret.size = 1; goto ret_ok; } goto loop; exit_loop: memcpy(ret.data, path.data, i); ret.size = i; ret_ok: _SET_IF_NOT_NULL(out_err, ERR_OK); return ret; } struct path path_join(struct path lhs, struct path rhs, enum err *out_err) { struct path path = {0}; if ( (lhs.size + rhs.size + 1) > PATH_SIZE_LIMIT ) { _SET_IF_NOT_NULL(out_err, ERR_TOO_BIG); return path; } /* TODO: Check if lhs or rhs have / at the end and start respectively */ path.size = (lhs.size + rhs.size + 1); memcpy(path.data, lhs.data, lhs.size); path.data[lhs.size] = '/'; memcpy(path.data + lhs.size + 1, rhs.data, rhs.size); return path; } struct path path_join_with_str(struct path lhs, struct str rhs, enum err *out_err) { struct path path = {0}; enum err err; path = path_from_str(rhs, &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return path; } return path_join(lhs, path, out_err); } struct path path_join_with_cstr(struct path lhs, const char *rhs, u64 rhs_size, enum err *out_err) { struct path path = {0}; enum err err; path = path_from_cstr(rhs, rhs_size, &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return path; } return path_join(lhs, path, out_err); } struct path path_join_with_cstr_ns(struct path lhs, const char *rhs, enum err *out_err) { struct path empty = {0}; struct path path = {0}; enum err err; _ARG_MUST_NOT_BE_NULL(rhs, out_err, empty); path = path_from_cstr_ns(rhs, &err); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return empty; } return path_join(lhs, path, out_err); } bool path_exists(struct path path, int (*access)(const char *, int)) { return access(path.data, F_OK) == 0; } bool path_can_read(struct path path, int (*access)(const char *, int)) { return access(path.data, R_OK) == 0; } bool path_can_write(struct path path, int (*access)(const char *, int)) { return access(path.data, W_OK) == 0; } bool path_can_execute(struct path path, int (*access)(const char *, int)) { return access(path.data, X_OK) == 0; } bool path_mkdir(struct path path, u32 mode, bool do_create_parents, int (*mkdir)(const char *, u32), enum err *out_err) { u64 i = 0; _ARG_MUST_NOT_BE_NULL(mkdir, out_err, false); if ( path.size == 1 ) { _SET_IF_NOT_NULL(out_err, ERR_PATH_INVALID); return 1; } if ( do_create_parents ) { for ( i = 1; i < path.size; ++i ) { if ( path.data[i] == '/' ) { path.data[i] = 0; mkdir(path.data, mode); path.data[i] = '/'; } } } if ( ! mkdir(path.data, mode) ) { _SET_IF_NOT_NULL(out_err, ERR_MKDIR_FAILED); return false; } _SET_IF_NOT_NULL(out_err, ERR_OK); return true; } /* bool path_touch(struct path path, int (*open)(const char *, int), enum err *out_err) { int fd = -1; _ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, false); _ARG_MUST_NOT_BE_NULL(open, out_err, false); fd = open(path.data, 0100 | 00644); if ( fd == -1 ) { _SET_IF_NOT_NULL(out_err, ERR_PATH_FAILED_OPEN); return false; } _SET_IF_NOT_NULL(out_err, ERR_OK); return true; } */ /* TODO: Replace this */ #include #include #include #include struct file path_file_read_all(const struct path *path, enum err *out_err) { struct file empty = {0}; struct file file = {0}; i64 file_size = -1; i32 fd = -1; _ARG_IF_NOT_NULL_MUST_BE(out_err, ERR_OK, empty); _ARG_MUST_NOT_BE_NULL(path, out_err, empty); fd = open(path->data, O_RDONLY); if ( fd < 0 ) { _SET_IF_NOT_NULL(out_err, ERR_FAILED_OPEN); goto exit_err; } file_size = lseek(fd, 0, SEEK_END); if ( file_size < 0 ) { _SET_IF_NOT_NULL(out_err, ERR_PATH_FILE_FAILED_SEEK); goto exit_err; } lseek(fd, 0, SEEK_SET); file.size = (u64) file_size; if ( file.size == 0 ) { _SET_IF_NOT_NULL(out_err, ERR_PATH_FILE_EMPTY); goto exit_err; } file.data = calloc(file.size + 1, sizeof(u8)); if ( file.data == NULL ) { _SET_IF_NOT_NULL(out_err, ERR_FAILED_ALLOC); goto exit_err; } { i64 rd = read(fd, file.data, file.size); if ( rd < 0 ) { _SET_IF_NOT_NULL(out_err, ERR_FAILED_READ); goto exit_err; } if ( rd == 0 ) { _SET_IF_NOT_NULL(out_err, ERR_PATH_FILE_EMPTY); goto exit_err; } } if ( close(fd) != 0 ) { /* It should be possible to handle EIO */ _SET_IF_NOT_NULL(out_err, ERR_FAILED_CLOSE); return empty; } _SET_IF_NOT_NULL(out_err, ERR_OK); return file; exit_err: if ( file.data != NULL ) { free(file.data); } if ( fd > 0 ) { if ( close(fd) != 0 ) { /* It should be possible to handle EIO */ _SET_IF_NOT_NULL(out_err, ERR_FAILED_CLOSE); return empty; } } return empty; } enum err path_file_save(const struct path *path, const struct file *file, enum err *out_err) { enum err err = ERR_OK; i64 wrote = -1; i32 fd = -1; _ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); _ARG_MUST_NOT_BE_NULL_SET_RET_ERR(path, out_err); _ARG_MUST_NOT_BE_NULL_SET_RET_ERR(file, out_err); fd = open(path->data, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if ( fd < 0 ) { err = ERR_FAILED_OPEN; goto exit; } wrote = write(fd, file->data, file->size); if ( wrote == -1 ) { err = ERR_FAILED_WRITE; goto exit; } if ( ((u64) wrote) != file->size ) { err = ERR_WROTE_WRONG_AMOUNT; goto exit; } err = ERR_OK; exit: if ( close(fd) != 0 ) { /* It should be possible to handle EIO */ err = ERR_FAILED_CLOSE; goto exit; } _SET_IF_NOT_NULL(out_err, err); return err; } # endif /* defined(WANT_PATH) || defined(WANT_ALL) */ /* ----------------------------- END PATH IMP ------------------------------ */ /* ---------------------------- START SGFX IMP ----------------------------- */ # if defined(WANT_SGFX) || defined(WANT_ALL) enum err sgfx_canvas_populate(struct sgfx_canvas *canvas, enum err *out_err) { _ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); _ARG_MUST_NOT_BE_NULL_SET_RET_ERR(canvas, out_err); canvas->width = SGFX_WIDTH; canvas->height = SGFX_HEIGHT; canvas->cap = SGFX_WIDTH * SGFX_HEIGHT; _SET_IF_NOT_NULL(out_err, ERR_OK) return ERR_OK; } enum err sgfx_canvas_fill(struct sgfx_canvas *canvas, u32 color, enum err *out_err) { u64 i = 0; _ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); _ARG_MUST_NOT_BE_NULL_SET_RET_ERR(canvas, out_err); for ( i = 0; i < canvas->cap; ++i ) { canvas->pixels[i] = color; } _SET_IF_NOT_NULL(out_err, ERR_OK) return ERR_OK; } enum err sgfx_canvas_fill_rect(struct sgfx_canvas *canvas, struct u64vec2 pos, struct u64vec2s size, u32 color, enum err *out_err) { u64 i = 0; u64 j = 0; u64 startp = 0; u64 endp = 0; _ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); _ARG_MUST_NOT_BE_NULL_SET_RET_ERR(canvas, out_err); /* TODO: Create a diferent error for when size lands outside canvas */ if ( pos.x > canvas->width || pos.y > canvas->height || (pos.x + size.w) > canvas->width || (pos.y + size.h) > canvas->height ) { _SET_IF_NOT_NULL(out_err, ERR_SGFX_POS_OUTSIDE_CANVAS); return ERR_SGFX_POS_OUTSIDE_CANVAS; } /* printf("pos.x -> %ld || pos.y -> %ld\n", pos.x, pos.y); printf("size.w -> %ld || size.h -> %ld\n", size.w, size.h); printf("(pos.x + size.w) -> %ld || (pos.y + size.h) -> %ld\n", (pos.x + size.w), (pos.y + size.h)); */ startp = (canvas->width * pos.y) + pos.x; endp = (canvas->width * (pos.y + size.h)) + (pos.x + size.w); if ( endp >= canvas->cap ) { endp = canvas->cap; } for ( i = startp; i < endp; i += canvas->width ) { for ( j = i; j < i+size.w; ++j ) { canvas->pixels[j] = color; } } _SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; } enum err sgfx_canvas_save_to_ppm(const struct sgfx_canvas *canvas, struct path path, enum err *out_err) { #define __T(s) s, cstr_len_max(s, 255, NULL, out_err) /* enum err err = ERR_OK; */ /* u64 i = 0; */ /* i32 fd = -1; */ (void) path; _ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); _ARG_MUST_NOT_BE_NULL_SET_RET_ERR(canvas, out_err); /* TODO: Check the errors */ /* fd = open(path.data, O_RDWR | O_CREAT, 00644); if ( err ) { _SET_IF_NOT_NULL(out_err, err); return err; } write(fd, __T("P6\n")); write(fd, __T(SGFX_WIDTH_CSTR"\n")); write(fd, __T(SGFX_HEIGHT_CSTR"\n")); write(fd, __T("255\n")); for ( i = 0; i < canvas->cap; ++i ) { struct sgfx_rgb rgb = {0}; rgb.r = (u8)(canvas->pixels[i] >> 24); rgb.g = (u8)(canvas->pixels[i] >> 16); rgb.b = (u8)(canvas->pixels[i] >> 8); write(fd, &rgb, sizeof(struct sgfx_rgb)); } close(fd); */ _SET_IF_NOT_NULL(out_err, ERR_OK); return ERR_OK; #undef __T } # endif /* defined(WANT_SGFX) || defined(WANT_ALL) */ /* ----------------------------- END SGFX IMP ------------------------------ */ /* --------------------------- START RAYLIB IMP ---------------------------- */ # if defined(WANT_RAYLIB) || defined(WANT_ALL) # if defined(RAYLIB_H) enum err raylib_draw_str(const struct str_builder *str, Font font, Vector2 position, float fontSize, float spacing, Color tint, enum err *out_err) { enum err err = ERR_OK; char *cstr = NULL; _ARG_IF_NOT_NULL_MUST_BE_RET_IT(out_err, ERR_OK); cstr = calloc(str->size + 1, sizeof(char)); if ( cstr == NULL ) { err = ERR_FAILED_ALLOC; goto exit; } memcpy(cstr, str->data, str->size); DrawTextEx(font, cstr, position, fontSize, spacing, tint); err = ERR_OK; exit: if ( cstr != NULL ) { free(cstr); } _SET_IF_NOT_NULL(out_err, err); return err; } # endif /* defined(RAYLIB_H) */ # endif /* defined(WANT_RAYLIB) || defined(WANT_ALL) */ /* ---------------------------- END RAYLIB IMP ----------------------------- */ # ifdef LIB_H_CTYPE # undef LIB_H_CTYPE # undef isspace # undef isdigit # endif /* LIB_H_CTYPE */ # ifdef LIB_H_STRING # undef LIB_H_STRING # undef memcpy # endif /* LIB_H_STRING */ # undef _SET_IF_NOT_NULL # undef _ARG_IF_NOT_NULL_MUST_BE # undef _ARG_MUST_NOT_BE_NULL # endif /* defined(IMP) || defined(IMP_STR) */ # ifdef LIB_H_ALLOC_FUNC # undef LIB_H_ALLOC_FUNC # undef ALLOC_FUNC # endif /* LIB_H_ALLOC_FUNC */ # ifdef LIB_H_STDBOOL # undef LIB_H_STDBOOL # undef bool # undef true # undef false # endif /* LIB_H_STDBOOL */ # ifdef LIB_H_NULL # undef LIB_H_NULL # undef NULL # endif /* LIB_H_NULL */ # ifdef LIB_H_UNISTD # undef LIB_H_UNISTD # undef R_OK # undef W_OK # undef X_OK # undef F_OK # endif /* LIB_H_UNISTD */ # ifdef LIB_H_STDINT # undef LIB_H_STDINT # undef intmax_t # endif /* LIB_H_STDINT */ #endif /* LIB_H */