Skip to content

Instantly share code, notes, and snippets.

@pavly-gerges
Last active October 5, 2025 00:01
Show Gist options
  • Save pavly-gerges/8f27443309daf4130cde4257dc88b4d1 to your computer and use it in GitHub Desktop.
Save pavly-gerges/8f27443309daf4130cde4257dc88b4d1 to your computer and use it in GitHub Desktop.

Constructional Design using State Machines

Author: Pavl G.

This document establishes a constructional design for a low-level IO API that operates on filesystems of all types; the constructional design is completely based on the computational automata theory, that focuses particularly on designing machines that automate algorithms with {predefined set of states $$Q$$, initial state $$q$$, transitioning function $$\delta$$, set of input symbols $$\Sigma$$, set of final accepting states $$F$$}. Conceptually, a language $$L$$ could be accepted from these set of final accepting states (e.g., on_eof_reached and on_error_encountered); the language $$L_M$$ is a set of all strings that could be recognized by its machine $$M$$; whose alphabets are the $$\Sigma$$.

Note

In this API; the language could be all the available strings for read/write IO operations from and to a filesystem. In which, the start string (or char depending on the implementation of the state machines) is the

The following is the an example for the implementation of the file_read algorithm that utilizes a dynamic way of determining the number of bytes to read using the file stat attributes:

image
/**
 * @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 <electrostatic/electronetsoft/util/filesystem/file_operations.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

static inline void update_file_postprocessor(file_mem *mem) {
    if (NULL == mem || mem->fd < 0) {
        return;
    }
    if (mem->n_bytes <= 0) {
        mem->n_bytes = 1;
    }
    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_read_bytes(file_mem *mem, ssize_t bytes) {
    fprintf(stdout, "Read Bytes: %s", mem->buffer);
}

static inline void on_eof_reached(file_mem *mem) {
    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 main() {
    fprintf(stdout, "Hello Fle Read Automata!\n");

    int fd = open("/home/pavl-g/Desktop/Glossary_for_AI", O_RDWR);

    if (fd < 0) {
        fprintf(stderr, "Error Encountered: %s\n", strerror(errno));
        exit(errno);
    }

    file_mem _file_mem = {
            .fd = fd,
            .trailing = '9',
            .buffer = NULL,
            .n_bytes = -1,
            .file_size = -1,
            .file_pos = -1
    };

    file_op_processor __processor = {
        .update_file_postprocessor = &update_file_postprocessor,
        .on_read_bytes = &on_read_bytes,
        .on_eof_reached = &on_eof_reached
    };

    status_code __status = read_into_mem(&_file_mem, &__processor);

    if (PASS != __status) {
        fprintf(stderr, "Error Encountered: %s\n", strerror(__status));
        exit(__status);
    }

    return 0;
}

[file_read.c]

#include <electrostatic/electronetsoft/util/filesystem/file_operations.h>
#include <electrostatic/electronetsoft/util/filesystem/file_status.h>

status_code read_into_mem(file_mem *mem, file_op_processor *processor) {
    // pre-processing automata -- Input validation
    if (mem->fd < 0) {
        return EUNDEFINEDBUFFER;
    }

    if (NULL != mem->buffer) {
        return -1;
    }

    // pre-processing automata -- Calculating the file size, current position,
                                // and the number of bytes to read
    status_code ___status = update_file_attrs(mem, processor);
    if (PASS != ___status) {
        return ___status;
    }

    if (NULL == mem->buffer) {
        return EUNDEFINEDBUFFER;
    }

    // processing automata -- Reading n_bytes into heap buffer
    //                        starting from the current file position
    while (1) {
        ssize_t read_bytes = 0;
        read_bytes = read(mem->fd, (mem->buffer + read_bytes), (mem->n_bytes - 1));
        // 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);
            }
            return errno;
        } else if (0 == read_bytes) {
            // EOF terminate!
            mem->buffer[mem->n_bytes - 1] = mem->trailing; /* add a null-terminating character */
            if (NULL != processor && NULL != processor->on_eof_reached) {
                processor->on_eof_reached(mem);
            }
            return PASS;
        } else if (read_bytes > 0) {
            // execute on_read
            if (NULL != processor && NULL != processor->on_read_bytes) {
                processor->on_read_bytes(mem, read_bytes);
            }
        }
    }
    return ASSERTION_FAILURE;
}
digraph FileReadingFSM {
rankdir=LR;
node [shape=circle, style=filled, fillcolor="#e6f2ff"];
// States
S0 [label="S0\nStart"];
S1 [label="S1\nfd < 0?"];
S2 [label="S2\nbuffer != NULL?"];
S3 [label="S3\nupdate_file_attrs"];
S4 [label="S4\nPASS?"];
S5 [label="S5\nbuffer == NULL?"];
S6 [label="S6\nRead Loop"];
S7 [label="S7\nread == -1"];
S8 [label="S8\nread == 0"];
S9 [label="S9\nread > 0"];
S10 [label="S10\nError Terminate", shape=doublecircle, fillcolor="#ffe6e6"];
S11 [label="S11\nEOF Terminate", shape=doublecircle, fillcolor="#e6ffe6"];
S12 [label="S12\nRead Callback"];
S13 [label="S13\nFinal", shape=doublecircle, fillcolor="#ffe6e6"];
// Transitions (pre-processing)
S0 -> S1 [label="entry"];
S1 -> S10 [label="fd < 0"];
S1 -> S2 [label="fd >= 0"];
S2 -> S10 [label="buffer != NULL"];
S2 -> S3 [label="buffer == NULL"];
S3 -> S4 [label="call update_file_attrs"];
S4 -> S10 [label="PASS != status"];
S4 -> S5 [label="PASS == status"];
S5 -> S10 [label="buffer == NULL"];
S5 -> S6 [label="buffer != NULL"];
// Read loop transitions
S6 -> S7 [label="read == -1"];
S6 -> S8 [label="read == 0"];
S6 -> S9 [label="read > 0"];
S7 -> S10 [label="on_error_encountered"];
S8 -> S11 [label="on_eof_reached"];
S9 -> S12 [label="on_read_bytes"];
S12 -> S6 [label="loop"];
// Termination
S10 -> S13 [label="return error"];
S11 -> S13 [label="return PASS"];
S6 -> S13 [label="ASSERTION_FAILURE (unreachable)"];
// Final state
S13 [shape=doublecircle, fillcolor="#ffe6e6"];
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment