Files
libakstdlib/src/stdlib.c

322 lines
11 KiB
C
Raw Normal View History

#include <akstdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
akerr_ErrorContext AKERR_NOIGNORE *aksl_malloc(size_t size, void **dst)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, dst, AKERR_NULLPOINTER, "NULL");
*dst = malloc(size);
FAIL_ZERO_RETURN(e, *dst, errno, "%ld bytes", size);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_free(void *ptr)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, ptr, AKERR_NULLPOINTER, "NULL");
free(ptr);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_memset(void *s, int c, size_t n)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, s, AKERR_NULLPOINTER, "s=%p", s);
FAIL_ZERO_RETURN(e, memset(s, c, n), errno, "Failed to memset");
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_memcpy(void *d, void *s, size_t n)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, d, AKERR_NULLPOINTER, "d=%p, s=%p", d, s);
FAIL_ZERO_RETURN(e, s, AKERR_NULLPOINTER, "d=%p, s=%p", d, s);
FAIL_ZERO_RETURN(e, (memcpy(d, s, n) == d), errno, "Failed to memcpy");
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_fopen(
char *pathname,
char *mode,
FILE **fp)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, fp, AKERR_NULLPOINTER, "NULL");
*fp = fopen(pathname, mode);
FAIL_ZERO_RETURN(e, *fp, errno, "%s", pathname);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_fread(
void *ptr,
size_t size, size_t nmemb,
FILE *fp)
{
size_t nmemr;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, fp, AKERR_NULLPOINTER, "NULL");
nmemr = fread(ptr, size, nmemb, fp);
if ( nmemr != nmemb ) {
FAIL_NONZERO_RETURN(e, feof(fp), AKERR_EOF, "EOF reached");
FAIL_NONZERO_RETURN(e, ferror(fp), AKERR_IO, "Error reading file");
}
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_fwrite(
void *ptr,
size_t size, size_t nmemb,
FILE *fp)
{
size_t nmemw;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, fp, AKERR_NULLPOINTER, "NULL argument");
nmemw = fwrite(ptr, size, nmemb, fp);
if ( nmemw != nmemb ) {
FAIL_NONZERO_RETURN(e, feof(fp), AKERR_EOF, "EOF reached");
FAIL_NONZERO_RETURN(e, ferror(fp), AKERR_IO, "Error reading file");
}
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_fclose(FILE *stream)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, stream, AKERR_NULLPOINTER, "NULL");
FAIL_NONZERO_RETURN(e, fclose(stream), errno, "Failed to fclose");
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_printf(int *count, const char *restrict format, ...)
{
va_list args;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, count, AKERR_NULLPOINTER, "count=%p, format=%p", (void *)count, (void *)format);
FAIL_ZERO_RETURN(e, format, AKERR_NULLPOINTER, "count=%p, format=%p", (void *)count, (void *)format);
va_start(args, format);
*count = vprintf(format, args);
FAIL_NONZERO_RETURN(e, (*count == -1), errno, "Short write");
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_fprintf(int *count, FILE *restrict stream, const char *restrict format, ...)
{
va_list args;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, count, AKERR_NULLPOINTER, "count=%p, stream=%p, format=%p", (void *)count, (void *)stream, (void *)format);
FAIL_ZERO_RETURN(e, stream, AKERR_NULLPOINTER, "count=%p, stream=%p, format=%p", (void *)count, (void *)stream, (void *)format);
FAIL_ZERO_RETURN(e, format, AKERR_NULLPOINTER, "count=%p, stream=%p, format=%p", (void *)count, (void *)stream, (void *)format);
va_start(args, format);
*count = vfprintf(stream, format, args);
FAIL_NONZERO_RETURN(e, (*count == -1), errno, "Short write");
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_sprintf(int *count, char *restrict str, const char *restrict format, ...)
{
va_list args;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, count, AKERR_NULLPOINTER, "count=%p, str=%p, format=%p", (void *)count, (void *)str, (void *)format);
FAIL_ZERO_RETURN(e, str, AKERR_NULLPOINTER, "count=%p, str=%p, format=%p", (void *)count, (void *)str, (void *)format);
FAIL_ZERO_RETURN(e, format, AKERR_NULLPOINTER, "count=%p, str=%p, format=%p", (void *)count, (void *)str, (void *)format);
va_start(args, format);
*count = vsprintf(str, format, args);
FAIL_NONZERO_RETURN(e, (*count == -1), errno, "Short write");
SUCCEED_RETURN(e);
}
2026-05-24 09:52:24 -04:00
akerr_ErrorContext AKERR_NOIGNORE *aksl_atoi(const char *nptr, int *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atoi(nptr);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_atol(const char *nptr, long *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atol(nptr);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_atoll(const char *nptr, long long *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atoll(nptr);
SUCCEED_RETURN(e);
}
2026-05-25 21:29:46 -04:00
akerr_ErrorContext AKERR_NOIGNORE *aksl_atof(const char *nptr, double *dest)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, nptr, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
FAIL_ZERO_RETURN(e, dest, AKERR_NULLPOINTER, "nptr=%p, dest=%p", (void *)nptr, (void *)dest);
*dest = atof(nptr);
SUCCEED_RETURN(e);
}
2026-05-24 09:52:24 -04:00
akerr_ErrorContext AKERR_NOIGNORE *aksl_realpath(const char *restrict path, char *restrict resolved_path)
{
char *result = NULL;
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, path, AKERR_NULLPOINTER, "path=%p, dest=%p", (void *)path, (void *)resolved_path);
result = realpath(path, resolved_path);
FAIL_ZERO_RETURN(e, result, errno, "path=%s, dest=%s", path, resolved_path);
2026-05-24 09:52:24 -04:00
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_push(aksl_ListNode *list, aksl_ListNode *obj)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list");
FAIL_ZERO_RETURN(e, obj, AKERR_NULLPOINTER, "obj");
aksl_ListNode *slow = list;
aksl_ListNode *fast = list;
aksl_ListNode *tail = list;
do {
if ( fast != NULL && fast->next != NULL ) {
fast = fast->next->next;
}
tail = slow;
slow = slow->next;
if ( fast != NULL && fast == slow) {
FAIL(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
}
} while ( slow != NULL || (fast != NULL && fast->next != NULL) );
tail->next = obj;
obj->next = NULL;
obj->prev = slow;
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_pop(aksl_ListNode *node)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, node, AKERR_NULLPOINTER, "node");
if ( node->prev != NULL ) {
node->prev->next = node->next;
}
if ( node->next != NULL ) {
node->next->prev = node->prev;
}
node->next = NULL;
node->prev = NULL;
SUCCEED_RETURN(e);
}
/**
* @brief Iterates over a tree structure in breadth or depth first order, executing a callback function on each node.
*
* This function recursively calls itself to traverse a binary tree datastructure.
*
* @param[in] root The tree structure to search
* @param[in] iter An aksl_TreeNodeIterator function which will be called for each node found
* @param[in] lalloc An aksl_AllocFunc function which will be used to allocate aksl_ListNode elements for the search, or NULL to use the default allocator (aksl_malloc)
* @param[in] lfree An aksl_FreeFunc function which will be used to free the elements procured with lalloc, or NULL to use the default free function (aksl_free)
* @param[in] searchmode One of the AKSL_TREE_SEARCH_BFS* defines
* @param[in] data Any user data that should be provided when the iterator is called
* @param[in] queue The linked list node to use as the head of the queue. The caller should pass NULL here.
*
* @throws AKERR_NULLPOINTER On null pointer inputs
* @return akerr_ErrorContext
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_tree_iterate(
aksl_TreeNode *root,
aksl_TreeNodeIterator iter,
aksl_AllocFunc lalloc,
aksl_FreeFunc lfree,
uint8_t searchmode,
void *data,
aksl_ListNode *queue)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, root, AKERR_NULLPOINTER, "root");
FAIL_ZERO_RETURN(e, iter, AKERR_NULLPOINTER, "iter");
if ( lalloc == NULL ) {
lalloc = &aksl_malloc;
}
if ( lfree == NULL ) {
lfree = &aksl_free;
}
switch ( searchmode ) {
case AKSL_TREE_SEARCH_DFS_PREORDER:
PASS(e, iter(root, data));
if ( root->left != NULL ) {
PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL));
}
if ( root-> right != NULL ) {
PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL));
}
break;
case AKSL_TREE_SEARCH_DFS_POSTORDER:
if ( root->left != NULL ) {
PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL));
}
if ( root-> right != NULL ) {
PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL));
}
PASS(e, iter(root, data));
break;
case AKSL_TREE_SEARCH_DFS_INORDER:
if ( root->left != NULL ) {
PASS(e, aksl_tree_iterate(root->left, iter, lalloc, lfree, searchmode, data, NULL));
}
PASS(e, iter(root, data));
if ( root-> right != NULL ) {
PASS(e, aksl_tree_iterate(root->right, iter, lalloc, lfree, searchmode, data, NULL));
}
break;
case AKSL_TREE_SEARCH_BFS:
case AKSL_TREE_SEARCH_BFS_RIGHT:
FAIL_RETURN(e, AKERR_NOT_IMPLEMENTED, "Searchmode %d", searchmode);
break;
}
SUCCEED_RETURN(e);
}
/**
* @brief Iterates over a linked list and execute a callback function on each node
*
* @param[in] list The linked list to iterate
* @param[in] iter An aksl_ListNodeIterator function which will be called for each node found
* @param[in] data Any user data that should be provided when the iterator is called
*
* @throws AKERR_NULLPOINTER on null pointer inputs
* @throws AKERR_CIRCULAR_REFERENCE when the linked list contains a circular reference
*
* @return akerr_ErrorContext
*/
akerr_ErrorContext AKERR_NOIGNORE *aksl_list_iterate(aksl_ListNode *list, aksl_ListNodeIterator iter, void *data)
{
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, list, AKERR_NULLPOINTER, "list");
FAIL_ZERO_RETURN(e, iter, AKERR_NULLPOINTER, "iter");
aksl_ListNode *slow = list;
aksl_ListNode *fast = list;
aksl_ListNode *tail = list;
do {
if ( fast != NULL && fast->next != NULL ) {
fast = fast->next->next;
}
PASS(e, iter(slow, data));
slow = slow->next;
if ( fast != NULL && fast == slow) {
FAIL(e, AKERR_CIRCULAR_REFERENCE, "%p", list);
}
} while ( slow != NULL || (fast != NULL && fast->next != NULL) );
SUCCEED_RETURN(e);
}