diff --git a/.studio-run-configs/test-fileread.run.xml b/.studio-run-configs/test-fileread.run.xml new file mode 100644 index 00000000..caf755d8 --- /dev/null +++ b/.studio-run-configs/test-fileread.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.studio-run-configs/test-filewrite.run.xml b/.studio-run-configs/test-filewrite.run.xml new file mode 100644 index 00000000..15076c54 --- /dev/null +++ b/.studio-run-configs/test-filewrite.run.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/adt/list.h b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/adt/list.h index e658737b..75d10908 100644 --- a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/adt/list.h +++ b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/adt/list.h @@ -43,11 +43,6 @@ extern "C" { #endif -enum list_type { - CONTIGUOUS_BUFFER, - LINKED_BUFFER -}; - struct list_element { void *data; void *metadata; diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/list/linked_buffer.h b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/list/linked_buffer.h index de2b89f6..563eee15 100644 --- a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/list/linked_buffer.h +++ b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/algorithm/arithmos/list/linked_buffer.h @@ -10,11 +10,6 @@ extern "C" { // disables the C++ name mangling #endif -enum linked_buffer_type { - SINGLE_ENDED, - DOUBLE_ENDED, -}; - struct linked_buffer { // no alignment issues // 64-bit (8 bytes) aligned structure diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_operations.h b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_operations.h new file mode 100644 index 00000000..a3e59474 --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_operations.h @@ -0,0 +1,119 @@ +/** + * @brief A completely memory-safe not internally synchronized API that provides a dynamic + * way of reading and writing to files without a [realloc] overhead; by delegating memory + * allocation as a part of the pre-processor states to the caller, and the memory deallocation or further reallocation calls + * as a part of the accepting states to another function of the caller API or Application. + * @note Synchronization (using polling or mutexes) could be introduced through the lifecycle struct + * [file_op_processor] for file operation processor. + * @author pavl_g. + * @date 2025-10 + */ +#ifndef _FILE_OPERATIONS_H_ +#define _FILE_OPERATIONS_H_ + +#ifndef _ELECTRO_MIO + +#ifdef __ANDROID__ +#define __off_t size_t +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +struct read_op_processor { + void (*on_bytes_processed)(file_mem *, ssize_t, void *); /* Executed on each successful read operation. */ + void (*on_eof_reached)(file_mem *); /* Executed when EOF is reached. Could be used to chain calls to memory deallocators. */ + void (*on_last_char_sampled)(file_mem *, void *caller); + void (*on_error_encountered)(file_mem *, int, void *caller); +}; + +struct write_op_processor { + void (*on_bytes_processed)(file_mem *, ssize_t, void *); /* Executed on each successful read operation. */ + void (*on_eob_reached)(file_mem *); + void (*on_last_char_sampled)(file_mem *, void *caller); + void (*on_error_encountered)(file_mem *, int, void *caller); +}; + +struct update_op_processor { + void (*on_update_nbytes)(file_mem *, ssize_t); /* Executed when updating the number of bytes attr (of the buffer for the file mem model) is commenced */ + void (*on_update_size)(file_mem *, __off_t); /* Executed when updating size is commenced. */ + void (*on_update_pos)(file_mem *, __off_t); /* Executed when updating the position is commenced. */ + void (*update_model_preprocessor)(file_mem *, void *caller); /* Executed */ + void (*update_model_postprocessor)(file_mem *, void *caller); /* Executed after the file mem model attrs update has finished. Could be used to chain calls to memory allocators. */ +}; + +struct serializer_op_processor { + void (*serializer_init_preprocessor)(pipe_serializer *); + void (*serializer_init_postprocessor)(pipe_serializer *); +}; + +struct file_mem { + int fd; + char trailing; /* The trailing byte of the buffer.*/ + ssize_t n_bytes; /* Total number of bytes to allocate for the buffer in memory + * including the number of read or write bytes + * starting from the current pos based on + * the file size, and the trailing byte. */ + ssize_t bytes_processed; + char *buffer; + __off_t file_size; /* Cached file size in bytes */ + __off_t file_pos; /* Cached file position */ + uint8_t __auto_update_attrs; /* Conditional flag to specify whether auto-update + * in the pre-processing stage is enabled. */ + uint8_t __continue_after_eof; /* Conditional flag to specify whether to continue after the EOF. */ +}; + +/** + * @brief A pipe-serializer object creates a pipe that has + * a write end and read end; both ends are mapped to the same + * filesystems, in which the write operations are available to be read + * by the memory model processor. Therefore, both memory models utilize + * a shared memory buffer, but they possess different filesystems and thus + * different file positions. + */ +struct pipe_serializer { + file_mem read_end; + file_mem write_end; +}; + + +/** + * @brief Delegates to allocate a heap buffer and reads a file identified by this file descriptor + * into the heap memory; returning the memory address into the + * [buffer] pointer of the file memory model object. + * + * @param mem a pointer to the file memory model struct. + * @param _processor a pointer to the file read operations processor; that links the API to the user application. + * @param __processor a pointer to the file attrs update processors. + */ +status_code read_into_mem(file_mem *, read_op_processor *, update_op_processor *); + +status_code update_file_attrs(file_mem *, update_op_processor *); + +/** + * @brief Writes a pre-allocated buffer to a file identified by a file descriptor from + * the file memory model structure; until reaching the trailing character which is excluded + * from the this write operation and marks the accepting state of this machine. + * + * @param mem a pointer to the file memory model struct. + * @param processor a pointer to the file operations processor; that links the API to the user application. + */ +status_code write_from_mem(file_mem *, write_op_processor *, update_op_processor *); + +status_code init_serializer(pipe_serializer *, serializer_op_processor *, update_op_processor *); + +#ifdef __cplusplus +} +#endif + +#endif +#endif \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_status.h b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_status.h new file mode 100644 index 00000000..a411d50f --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_status.h @@ -0,0 +1,47 @@ +#ifndef _FILE_ATTRS_H_ +#define _FILE_ATTRS_H_ + +#ifndef _ELECTRO_MIO + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include + +static inline status_code get_file_bytes(int fd, __off_t *__size) { + if (fd < 0 || NULL == __size) { + return EUNDEFINEDBUFFER; + } + struct stat statbuf; + int __status = fstat(fd, &statbuf); + if (__status != 0) { + return errno; + } + *__size = statbuf.st_size; + + return PASS; +} + +static inline status_code get_file_pos(int fd, off_t *__offset) { + if (fd < 0 || NULL == __offset) { + return EUNDEFINEDBUFFER; + } + *__offset = lseek(fd, 0, SEEK_CUR); + if (*__offset < 0) { + return errno; + } + return PASS; +} + +#ifdef __cplusplus +} +#endif + +#endif +#endif \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_verify.h b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_verify.h index 6a2cfc24..52d49b33 100644 --- a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_verify.h +++ b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/filesystem/file_verify.h @@ -1,6 +1,8 @@ #ifndef _FILE_VERIFY_H_ #define _FILE_VERIFY_H_ +#ifndef _ELECTRO_MIO + #ifdef __cplusplus extern "C" { #endif @@ -145,4 +147,5 @@ static inline int is_fsymbolic_link(int fd) { } #endif +#endif #endif \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/types.h b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/types.h index 3af73796..a9628341 100644 --- a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/types.h +++ b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/types.h @@ -8,6 +8,8 @@ #ifndef __TYPES_H_ #define __TYPES_H_ +#include + #ifdef __cplusplus extern "C" { // disables C++ Name Mangling #endif @@ -15,13 +17,22 @@ extern "C" { // disables C++ Name Mangling // Abstract Data Types for Lists typedef struct list (list); typedef struct list_info (list_info); -typedef enum list_type (list_type); + +typedef enum list_type { + CONTIGUOUS_BUFFER, + LINKED_BUFFER +} list_type; + typedef struct list_element (list_element); typedef struct list_function_table (list_function_table); // Concretized types for linked buffers typedef struct linked_buffer (linked_buffer); -typedef enum linked_buffer_type (linked_buffer_type); + +typedef enum linked_buffer_type { + SINGLE_ENDED, + DOUBLE_ENDED, +} linked_buffer_type; // Abstract types for Mathematical Graph Structures typedef struct vertex (vertex); @@ -45,8 +56,23 @@ typedef struct dijkstra_structure (dijkstra_structure); typedef struct api_lifecycle (api_lifecycle); typedef struct typed_pointer (typed_pointer); typedef union pointer (pointer); -typedef enum pointer_type (pointer_type); -typedef enum status_code (status_code); + +typedef enum status_code { + PASS = INT32_MAX, + EUNDEFINEDBUFFER = INT32_MIN, + EEMPTYBUFFER = (EUNDEFINEDBUFFER + 1), + EFULLBUFFER = (EEMPTYBUFFER + 1), + EINCOMPATTYPE = (EFULLBUFFER + 1), + ENOELEMENT = (EINCOMPATTYPE + 1), + EBUFFERTURNCATION = (ENOELEMENT + 1), + EBUFFEROVERFLOW = (EBUFFERTURNCATION + 1), + EDLLOPENFAIL = (EBUFFEROVERFLOW + 1), + EDLLSYMFAIL = (EDLLOPENFAIL + 1), + EDLLCONVENTIONCALLRETURN = (EDLLSYMFAIL + 1), + UNEXPECTED_ERROR = (EDLLCONVENTIONCALLRETURN + 1), + ASSERTION_SUCCESS = 1, + ASSERTION_FAILURE = 0 +} status_code; typedef struct memory_partition (memory_partition); @@ -55,6 +81,14 @@ typedef struct routine_data (routine_data); typedef struct dll_function_table (dll_function_table); typedef struct routine_callbacks (routine_callbacks); +typedef struct write_op_processor (write_op_processor); +typedef struct read_op_processor (read_op_processor); +typedef struct update_op_processor (update_op_processor); + +typedef struct serializer_op_processor (serializer_op_processor); +typedef struct file_mem (file_mem); +typedef struct pipe_serializer (pipe_serializer); + // Types for Vector Maths Libraries typedef struct vector2d (vector2d); diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/utilities.h b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/utilities.h index 4d31dc63..210b28e2 100644 --- a/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/utilities.h +++ b/electrostatic-sandbox-framework/electrostatic-core/src/include/electrostatic/electronetsoft/util/utilities.h @@ -19,35 +19,19 @@ union pointer { list_function_table *m_list_function_table; }; -enum pointer_type { +typedef enum pointer_type { TYPE_LIST = 200, TYPE_LIST_ELEMENT = TYPE_LIST + 1, TYPE_LINKED_BUFFER = TYPE_LIST_ELEMENT + 1, TYPE_LIST_FUNCTION_TABLE = TYPE_LINKED_BUFFER + 1, TYPE_UNKNOWN = TYPE_LIST_FUNCTION_TABLE + 1, -}; +} pointer_type; struct typed_pointer { pointer address; pointer_type type; }; -enum status_code { - PASS = INT32_MAX, - EUNDEFINEDBUFFER = INT32_MIN, - EEMPTYBUFFER = (EUNDEFINEDBUFFER + 1), - EFULLBUFFER = (EEMPTYBUFFER + 1), - EINCOMPATTYPE = (EFULLBUFFER + 1), - ENOELEMENT = (EINCOMPATTYPE + 1), - EBUFFERTURNCATION = (ENOELEMENT + 1), - EBUFFEROVERFLOW = (EBUFFERTURNCATION + 1), - EDLLOPENFAIL = (EBUFFEROVERFLOW + 1), - EDLLSYMFAIL = (EDLLOPENFAIL + 1), - EDLLCONVENTIONCALLRETURN = (EDLLSYMFAIL + 1), - ASSERTION_SUCCESS = 1, - ASSERTION_FAILURE = 0 -}; - struct api_lifecycle { void (*on_operation_succeeded)(void *api, void *caller); void (*on_operation_failed)(void *api, void *caller, status_code cause); @@ -60,7 +44,7 @@ struct api_lifecycle { * @param address a pointer variable for a memory address. * @return an r-value that is a runtime constant representing the address. */ -static inline void *const rvalue(void *address) { +static inline void *rvalue(void *address) { return (void *const) address; } @@ -88,7 +72,7 @@ static inline void *const rvalue(void *address) { static inline bool is_pass(status_code **codes) { // preprocessing automata if (rvalue(codes) == NULL || - rvalue(*codes) == NULL) { + rvalue(*codes) == NULL) { return false; } // preprocessing initialize with true for @@ -103,18 +87,17 @@ static inline bool is_pass(status_code **codes) { } static inline typed_pointer get_typed_pointer(void *address, pointer_type type) { + typed_pointer pointer; // preprocessor automata -- Input Validation. if (rvalue(address) == NULL) { - return (typed_pointer) { - .address.m_list = NULL, - .type = TYPE_UNKNOWN - }; + pointer.address.m_list = NULL; + pointer.type = TYPE_UNKNOWN; + return pointer; } // processing automata -- returning a typed pointer - return (typed_pointer) { - .address.m_list = address, - .type = type - }; + pointer.address.m_list = (list *) address; + pointer.type = type; + return pointer; } #ifdef __cplusplus diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_read.c b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_read.c new file mode 100644 index 00000000..404f7dd9 --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_read.c @@ -0,0 +1,86 @@ +#include +#include +#include + +status_code read_into_mem(file_mem *mem, + read_op_processor *_processor, + update_op_processor *__processor) { + // pre-processing automata -- Input validation + if (rvalue(mem) == NULL) { + return EUNDEFINEDBUFFER; + } + + if (NULL != __processor && NULL != __processor->update_model_preprocessor) { + __processor->update_model_preprocessor(mem, &read_into_mem); + } + + // pre-processing automata -- Calculating the file size, current position, + // and the number of bytes to read + if (mem->__auto_update_attrs) { + status_code ___status = update_file_attrs(mem, __processor); + if (PASS != ___status) { + return ___status; + } + } + + // postprocessing automata -- Invoke the update file postprocessor + if (NULL != __processor && NULL != __processor->update_model_postprocessor) { + __processor->update_model_postprocessor(mem, &read_into_mem); + } + + if (NULL == mem->buffer) { + return EUNDEFINEDBUFFER; + } + + // processing automata -- Reading n_bytes into heap buffer + // starting from the current file position + ssize_t read_bytes = 0; + ssize_t total_bytes = 0; + while (1) { + read_bytes = read(mem->fd, (mem->buffer + total_bytes), /* Advance linearly over the File Mem model buffer + * with the read bytes */ + (mem->n_bytes - 1) - total_bytes); /* Retro-advance on the number of available bytes + * on the corresponding physical file model. */ + + total_bytes += read_bytes; + mem->bytes_processed = total_bytes; + // post processing automata + + if (-1 == read_bytes) { + // terminated with error; report error! + if (NULL != _processor && NULL != _processor->on_error_encountered) { + _processor->on_error_encountered(mem, errno, &read_into_mem); + } + return errno; + } else if (0 == read_bytes) { + // EOF terminate! + mem->buffer[total_bytes] = mem->trailing; /* add a null-terminating character */ + if (NULL != _processor && NULL != _processor->on_eof_reached) { + _processor->on_eof_reached(mem); + } + // post-processing sub-state (HACK!) + if (mem->__continue_after_eof) { + continue; + } + return PASS; + } else if (read_bytes > 0) { + // execute on_read + if (NULL != _processor && NULL != _processor->on_bytes_processed) { + _processor->on_bytes_processed(mem, read_bytes, &read_into_mem); + } + + // sample out if all the requested characters are read + // even though the EOF is not reached, yet. + if ((mem->n_bytes - 1) == total_bytes) { + mem->buffer[total_bytes] = mem->trailing; /* add a null-terminating character */ + if (NULL != _processor && NULL != _processor->on_last_char_sampled) { + _processor->on_last_char_sampled(mem, &read_into_mem); + } + } + } else { + return UNEXPECTED_ERROR; + } + } + + return ASSERTION_FAILURE; +} \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_serializer.c b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_serializer.c new file mode 100644 index 00000000..36e06b47 --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_serializer.c @@ -0,0 +1,34 @@ +#include +#include + +status_code init_serializer(pipe_serializer *serializer, + serializer_op_processor *_processor, + update_op_processor *__processor) { + if (NULL == serializer) { + return EUNDEFINEDBUFFER; + } + + if (NULL != _processor && NULL != _processor->serializer_init_preprocessor) { + _processor->serializer_init_preprocessor(serializer); + } + + if (serializer->read_end.fd == serializer->write_end.fd) { + return -1; + } + + status_code ___status = update_file_attrs(&serializer->read_end, __processor); + if (PASS != ___status) { + return ___status; + } + + ___status = update_file_attrs(&serializer->write_end, __processor); + if (PASS != ___status) { + return ___status; + } + + if (NULL != _processor && NULL != _processor->serializer_init_postprocessor) { + _processor->serializer_init_postprocessor(serializer); + } + + return PASS; +} \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_update.c b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_update.c new file mode 100644 index 00000000..abe5c6ee --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_update.c @@ -0,0 +1,54 @@ +#include +#include +#include + +status_code update_file_attrs(file_mem *mem, + update_op_processor *_processor) { + // pre-processing automata -- Input Validation + if (rvalue(mem) == NULL) { + return EUNDEFINEDBUFFER; + } + + if (mem->fd < 0 || !is_fexistential(mem->fd)) { + return EUNDEFINEDBUFFER; + } + + // pre-processing automata -- Comparing Values + __off_t __pos; + status_code __status = get_file_pos(mem->fd, &__pos); + if (PASS != __status) { + __pos = 0; + } + + __off_t __size; + __status = get_file_bytes(mem->fd, &__size); + if (PASS != __status) { + return __status; + } + + if (mem->file_pos != __pos) { + __off_t __old = mem->file_pos; + mem->file_pos = __pos; + if (NULL != _processor && NULL != _processor->on_update_pos) { + _processor->on_update_pos(mem, __old); + } + } + + if (mem->file_size != __size) { + __off_t __old = mem->file_size; + mem->file_size = __size; + if (NULL != _processor && NULL != _processor->on_update_size) { + _processor->on_update_size(mem, __old); + } + } + + if (mem->n_bytes != (__size - __pos)) { + ssize_t __old = mem->n_bytes; + mem->n_bytes = (__size - __pos) + 1; + if (NULL != _processor && NULL != _processor->on_update_nbytes) { + _processor->on_update_nbytes(mem, __old); + } + } + + return PASS; +} \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_write.c b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_write.c new file mode 100644 index 00000000..c4d5fc44 --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-core/src/libs/electrostatic-primer/electronetsoft/util/filesystem/file_write.c @@ -0,0 +1,82 @@ +#include +#include +#include + +status_code write_from_mem(file_mem *mem, + write_op_processor *_processor, + update_op_processor *__processor) { + // pre-processing automata -- Input validation + if (rvalue(mem) == NULL) { + return EUNDEFINEDBUFFER; + } + + if (NULL != __processor && NULL != __processor->update_model_preprocessor) { + __processor->update_model_preprocessor(mem, &write_from_mem); + } + + if (mem->fd < 0 || !is_fexistential(mem->fd)) { + return UNEXPECTED_ERROR; + } + + if (NULL == mem->buffer) { + return EUNDEFINEDBUFFER; + } + + // processing automata -- Write Characters until the trailing char is reached + // NB: This is also known as write using polling! + // On the other hand, there is write using IRQ aka. interrupt requests; + // Soft IRQs are analogous to Process Signal Handlers; it's mediated by a Kernel + // software trap. + // R/W IO using Soft IRQs are covered within the [soft_irq] API. + ssize_t written_bytes = 0; + ssize_t total_bytes = 0; + while (1) { + if (*(mem->buffer + total_bytes) == mem->trailing) { + if (NULL != _processor && NULL != _processor->on_eob_reached) { + _processor->on_eob_reached(mem); + } + break; + } + + written_bytes = write(mem->fd, + (const void *) + (mem->buffer + total_bytes), + (mem->n_bytes - 1) - total_bytes); + total_bytes += written_bytes; + // post-processing sub-machines -- Validate the state of the write bytes. + if (written_bytes <= 0) { + // Error encountered, report and terminate! + if (NULL != _processor && NULL != _processor->on_error_encountered) { + _processor->on_error_encountered(mem, errno, &write_from_mem); + } + return errno; + } else if (written_bytes > 0) { + // Execute lifecycle processors, try processing more bytes until all requested bytes are written. + if (NULL != _processor && NULL != _processor->on_bytes_processed) { + _processor->on_bytes_processed(mem, written_bytes, &write_from_mem); + } + } else if (total_bytes == (mem->n_bytes - 1)) { + // All bytes are written? -> terminate + // Equivalent to EOF. + if (NULL != _processor && NULL != _processor->on_eob_reached) { + _processor->on_eob_reached(mem); + } + break; + } else { + return UNEXPECTED_ERROR; + } + } + + // post-processing -- Update the file attrs + status_code ___status = update_file_attrs(mem, __processor); + if (PASS != ___status) { + return ___status; + } + + // postprocessing automata -- Invoke the update file postprocessor + if (NULL != __processor && NULL != __processor->update_model_postprocessor) { + __processor->update_model_postprocessor(mem, &write_from_mem); + } + + return PASS; +} \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_file_read.c b/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_file_read.c new file mode 100644 index 00000000..c6c58496 --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_file_read.c @@ -0,0 +1,108 @@ +/** + * @brief A tech=demo for the implementation of the file reading algorithm that provides a dynamic algorithm of determining the number of bytes to read out of a file using the file stat attributes from the Unix Standard library by requesting a call to the file status utility. + * @author pavl_g. + * @date 10-2025 + */ +#include +#include +#include +#include +#include +#include +#include + +static inline void update_model_preprocessor(file_mem *mem, void *caller) { + if (caller != &read_into_mem) { + return; + } + + int fd = open("/etc/bash.bashrc", O_RDONLY); + + if (fd < 0) { + fprintf(stderr, "Error Encountered: %s\n", strerror(errno)); + exit(errno); + } + + mem->fd = fd; +} + +static inline void update_model_postprocessor(file_mem *mem, void *caller) { + if (caller != &read_into_mem) { + return; + } + + if (mem->fd == STDIN_FILENO) { + mem->n_bytes = 2; // two bytes are given; the leading and the trailing byte. + // marking the start and the end of the string buffer + } + fprintf(stdout, "Size of memory buffer (in bytes) = %zd\n", + mem->n_bytes); + mem->buffer = calloc(mem->n_bytes, sizeof (char)); + + if (NULL == mem->buffer) { + return; + } +} + +static inline void on_bytes_processed(file_mem *mem, + ssize_t bytes, void *caller) { + if (caller != &read_into_mem) { + return; + } + fprintf(stdout, "Read bytes = %s\n", mem->buffer); +} + +static inline void on_eof_reached(file_mem *mem) { + // support for stdin + if (mem->fd == STDIN_FILENO && mem->n_bytes < 20) { + mem->n_bytes += mem->n_bytes; + mem->buffer = realloc(mem->buffer, mem->n_bytes); + return; + } + fprintf(stdout, "Read Bytes after EOF: %s\n", mem->buffer); + fprintf(stdout, "EOF Reached!\n"); + // deallocates memory here! + if (NULL != mem->buffer) { + free(mem->buffer); + mem->buffer = NULL; + } + int __status = close(mem->fd); + if (0 != __status) { + fprintf(stderr, "Error Encountered: %s\n", strerror(__status)); + exit(__status); + } +} + +int main() { + fprintf(stdout, "Hello File Read Automata!\n"); + + file_mem _file_mem = { + .fd = -1, + .trailing = '\0', + .buffer = NULL, + .n_bytes = -1, + .file_size = -1, + .file_pos = -1, + .__auto_update_attrs = 1, + .__continue_after_eof = 0 + }; + + read_op_processor _processor = { + .on_bytes_processed = &on_bytes_processed, + .on_eof_reached = &on_eof_reached + }; + + update_op_processor __processor = { + .update_model_preprocessor = &update_model_preprocessor, + .update_model_postprocessor = &update_model_postprocessor, + }; + + status_code __status = read_into_mem(&_file_mem, &_processor, &__processor); + + if (PASS != __status) { + fprintf(stderr, "Error Encountered: %s\n", strerror(__status)); + exit(__status); + } + + return 0; +} \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_file_write.c b/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_file_write.c new file mode 100644 index 00000000..78954baa --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_file_write.c @@ -0,0 +1,90 @@ +/** + * @brief A tech-demo for the implementation of the file writing algorithm using polling that provides an algorithm to write out a buffer to a file and a post processing automata to update the file attributes using the file stat attributes from the Unix Standard library by requesting a call to the file status utility. + * @author pavl_g. + * @date 10-2025 + */ +#include +#include +#include +#include +#include +#include +#include + +static inline void update_model_preprocessor(file_mem *mem, + void *caller) { + if (caller != &write_from_mem) { + return; + } + + int fd = open("/home/pavl-g/Desktop/test.txt", O_RDWR | O_CREAT); + + if (fd < 0) { + fprintf(stderr, "Error Encountered: %s\n", strerror(errno)); + exit(errno); + } + + mem->fd = fd; + lseek(mem->fd, 0, SEEK_END); // append! + + mem->buffer = "Hello from Project: ElectroNetSoft, File Memory Modelling API.\n"; + mem->n_bytes = strlen(mem->buffer) + 1; + + fprintf(stdout, "Size of memory buffer (in bytes) = %zd\n", + mem->n_bytes); +} + +static inline void on_bytes_processed(file_mem *mem, ssize_t bytes, + void *caller) { + if (caller != &write_from_mem) { + return; + } + + fprintf(stdout, "%s", mem->buffer); +} + +static inline void on_eob_reached(file_mem *mem) { + fprintf(stdout, "EOB Reached!\n"); +} + +static inline void update_model_postprocessor(file_mem *mem, + void *caller) { + if (caller != &write_from_mem) { + return; + } + close(mem->fd); + mem->fd = -1; +} + +int main() { + fprintf(stdout, "Hello File Write Automata!\n"); + + file_mem _file_mem = { + .fd = -1, + .trailing = '\0', + .buffer = NULL, + .n_bytes = -1, + .file_size = -1, + .file_pos = -1, + .__auto_update_attrs = 1, + }; + + write_op_processor _processor = { + .on_bytes_processed = &on_bytes_processed, + .on_eob_reached = &on_eob_reached, + }; + + update_op_processor __processor = { + .update_model_preprocessor = &update_model_preprocessor, + .update_model_postprocessor = &update_model_postprocessor, + }; + + status_code __status = write_from_mem(&_file_mem, &_processor, &__processor); + + if (PASS != __status) { + fprintf(stderr, "Error Encountered: %s\n", strerror(__status)); + exit(__status); + } + + return 0; +} \ No newline at end of file diff --git a/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_process_serialization.c b/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_process_serialization.c new file mode 100644 index 00000000..fa938ce0 --- /dev/null +++ b/electrostatic-sandbox-framework/electrostatic-examples/src/linux/hello_process_serialization.c @@ -0,0 +1,141 @@ +/** + * @brief This example creates a physical pipe and serializes data + * between 2 processes over the off-heap memory. Synchronization and concurrency + * is implemented utilizing Polling over a boolean flag on the lifecycle pattern + * of the read_op component. + * + * @author pavl_g. + */ +#include +#include +#include +#include +#include +#include + +static inline void on_error_encountered(file_mem *mem, int err, void *caller) { + fprintf(stderr, "%s\n", strerror(err)); +} + +static inline void on_eof_reached(file_mem *mem) { + // -------- Start the polling block -------- + uint8_t __predicate = mem->bytes_processed == 0; + if (__predicate) { + mem->__continue_after_eof = 1; + // -------- Connect the polling block to the read automaton -------- + return; + } + // -------- End of the polling block -------- + fprintf(stdout, "Read process = %s\n", mem->buffer); + free(mem->buffer); + mem->buffer = NULL; + mem->__continue_after_eof = 0; + + close(mem->fd); +} + +static inline void on_eob_reached(file_mem *mem) { + fprintf(stdout, "Write process = %s", mem->buffer); + close(mem->fd); +} + +static inline void on_last_char_sampled(file_mem *mem, void *caller) { + mem->n_bytes += mem->n_bytes; + mem->buffer = realloc(mem->buffer, sizeof (char) * (mem->n_bytes)); +} + +static inline void on_bytes_processed(file_mem *mem, ssize_t bytes, + void *caller) { +} + +static inline void writing_process(pipe_serializer *serializer) { + + serializer->write_end.buffer = "Hello From the Electrostatic-Sandbox SDK Pipe Serializer...\n"; + serializer->write_end.n_bytes = strlen(serializer->write_end.buffer) + 1; + + sleep(10); // simulate jobs by sleeping the process + + write_from_mem(&serializer->write_end, &(write_op_processor ) { + .on_eob_reached = &on_eob_reached, + .on_bytes_processed = &on_bytes_processed + }, NULL); +} + +static inline void reading_process(pipe_serializer *serializer) { + + serializer->read_end.n_bytes = 2; + serializer->read_end.buffer = calloc(serializer->read_end.n_bytes, sizeof (char)); + + if (serializer->read_end.buffer == NULL) { + fprintf(stderr, "Error: %s\n", strerror(errno)); + exit(errno); + } + + status_code __status = read_into_mem(&serializer->read_end, &(read_op_processor) { + .on_eof_reached = &on_eof_reached, + .on_last_char_sampled = &on_last_char_sampled, + .on_bytes_processed = &on_bytes_processed, + .on_error_encountered = &on_error_encountered + }, NULL); + + if (PASS != __status) { + fprintf(stderr, "%s\n", strerror(__status)); + exit(errno); + } +} + +static inline void serializer_init_preprocessor(pipe_serializer *serializer) { + // preprocessing check the file and remove it if it exists + // for the test and the showcase + +} + +static inline void serializer_init_postprocessor(pipe_serializer *serializer) { + // do the read/write testing here! + serializer->write_end.fd = open("/home/pavl-g/Desktop/test.txt", O_RDWR | O_CREAT); + serializer->read_end.fd = open("/home/pavl-g/Desktop/test.txt", O_RDONLY); + + // start another process + pid_t pid = fork(); + if (pid > 0) { // parent process + writing_process(serializer); + } else if (pid == 0) { // subprocess + reading_process(serializer); + } else { + + } +} + + +int main() { + pipe_serializer serializer = { + .read_end = (file_mem) { + .fd = -1, + .trailing = '\0', + .buffer = NULL, + .n_bytes = -1, + .__auto_update_attrs = 0 + }, + .write_end = (file_mem) { + .fd = -1, + .trailing = '\0', + .buffer = NULL, + .n_bytes = -1 + } + }; + + serializer_op_processor _processor = { + .serializer_init_preprocessor = &serializer_init_preprocessor, + .serializer_init_postprocessor = &serializer_init_postprocessor + }; + + update_op_processor __processor = { + }; + + status_code __status_code = init_serializer(&serializer, &_processor, &__processor); + if (PASS != __status_code) { + return __status_code; + } + + return 0; +} \ No newline at end of file diff --git a/helper-scripts/project-impl/compile-all-mcu.sh b/helper-scripts/project-impl/compile-all-mcu.sh index ab42f38a..83293cfa 100755 --- a/helper-scripts/project-impl/compile-all-mcu.sh +++ b/helper-scripts/project-impl/compile-all-mcu.sh @@ -15,7 +15,7 @@ electroio="$(pwd)/electrostatic-sandbox-framework/${source_dir}/src/libs/electro platform_module="${electronetsoft}/platform/linux/" comm_module="${electronetsoft}/comm/" algorithm_module="${electronetsoft}/algorithm/" -util_module="${electronetsoft}/util/" +util_module="${electronetsoft}/util/unit-testing" electromio_module="${electroio}/electromio/" ./helper-scripts/project-impl/compile-electrostatic.sh \