Add utilities and documentation

Add portable filesize and logging C libraries and documentation for development.
This commit is contained in:
Aidan C. Mullen 2025-03-06 19:55:35 -05:00
parent 724659b25f
commit d460a7ca93
12 changed files with 627 additions and 283806 deletions

34
.gitignore vendored
View file

@ -11,7 +11,6 @@
!build.sh
!CHANGELOG
!configure.ac
!extension_api.json
!LICENSE
!Makefile.am
!README
@ -34,12 +33,21 @@
!/bld/src/d/dub.sdl
!/bld/src/d/dub.selections.json
# /docs
!/docs/
/docs/*
# /doc
!/doc/
/doc/*
!/docs/1.1_ACKNOWLEDGMENTS
!/docs/1.2_PRIVACY
!/doc/1.1_ACKNOWLEDGMENTS
!/doc/1.2_PRIVACY
# /doc/2.0_DEVELOPMENT
!/doc/2.0_DEVELOPMENT/
/doc/2.0_DEVELOPMENT/*
!/doc/2.0_DEVELOPMENT/2.1_VERSIONING
!/doc/2.0_DEVELOPMENT/2.3_EXTENSIONS
!/doc/2.0_DEVELOPMENT/2.5_LANGUAGE
!/doc/2.0_DEVELOPMENT/2.7_LIBRARIES
# /engine
!/engine/
@ -73,6 +81,20 @@
!/src/main.gdextension
!/src/main.h
# /src/filesize
!/src/filesize
/src/filesize/*
!/src/filesize/size.c
!/src/filesize/
# /src/logging
!/src/logging
/src/logging/*
!/src/logging/logging.c
!/src/logging/logging.h
# /src/init
!/src/init
/src/init/*

View file

@ -0,0 +1,90 @@
2.1 VERSIONING
==============
The version-scheme used to track progress.
I. Basic Structure
------------------
u.v.w-x.y
Major Version
The first number, "u" in the example, represents the current major
version. A major version of "0" means that the software is not fully
complete; it's only incremented when backwards compatibility is lost.
Minor Version
Minor versions utilize the second number, "v" in the example,
and are incremented when new features are added.
Patch
Patches, "w" in the example, are generally small releases that only
fix bugs and make small improvements to the existing feature-set.
Pre-Releases
Preleases fill-in the "x" and "y" in the example. These indicate
that the release is either an alpha or a beta, meaning that it is
unfinished or not fully tested. To continue, the suffix (x), will be
replaced with an "a" for alpha releases, a "b" for betas, and an "rc"
for release candidates. To iterate, the "y" is substituted with a
number that is incremented with each passing alpha or beta release.
Please note that the "-x.y" extension is only added for pre-releases,
and is absent in stable versions.
Full Example
1.3.7-b.4
Represents the fourth beta of the seventh patch for the third
minor version of the first major release.
II. Branches
------------
This software utilizes branches in order to organize new features and
remove bugs as they move down the "pipeline" or "stream".
Pre-Alpha
All new features begin within their own Git branches. This allows
them to be contained and prevent breakage caused by other features. Once
an extremely early version of the feature is complete, it is moved into
the "Alpha" branch.
Alpha
During the "Alpha" stage, features will most likely be buggy and
more prone to problems; the goal of alphas in this project is to fix any
critical bugs and complete the feature. During this phase, features
are merged into a staging branch that will eventually become the future
"stable" branch.
Formatting: x.y.z-a.x
Beta
The "Beta" stage comes once a feature is complete, but still needs
further testing. The "freeze" applied to further development of the
feature prevents excess bugs from appearing.
Formatting: x.y.z-b.x
Release Candidate
By this stage, critical issues have been resolved, leaving only
final testing to be done.
Patches begin here, as they do not require a full alpha or beta build.
Formatting: x.y.z-rc.x
Stable
"Stable" is the end-user release and is based on the branch of the
same name.
--- end of 2.1 VERSIONING ---

View file

@ -0,0 +1,11 @@
2.3 EXTENSIONS
==============
For extensions minimal and embeddable scripting language is ideal. For
this reason Lua is the preferred langauge with regard to extending the
application, as it is extremely small, allowing for minimal overhead and
employment in minimized builds; written in ANSI-C89, so it will run on virtually
any platform dating back aged legacy systems; and has a profoundly
apprehensive C API, which allows for trivial integration with minimal friction.
--- end of 2.3 EXTENSIONS ---

View file

@ -0,0 +1,56 @@
2.5 LANGUAGE
============
DISCLAIMER: this file must be updated and adapted to this project.
I. Organized Codebase
---------------------
The program is primarily written in C, and is dispersed into a variety of
optional modules; therefore, the inclusion of other languages, dialects, and
platform-dependent components are permitted.
This project's core and a number of its direct dependencies conform to ISO
9899:1990, which is generally referred to as Standard C90, and is functionally
identical to ANSI X3.159-1989 "Programming Language C", which is Standard
C89/ANSI-C. This ensures compatibilty between the basic functionality of the
application and legacy/"retro" platforms, which support is planned for.
In the project's core, dialect-dependent features should be omitted, unless
they are included within a preprocessor-directive that optionalizes their
implmentation and separates their influence from the vital structure of the
program.
Other languages and C-dialects can be used, but they must conform to the
modular nature and goals of the program. By default, all extraneous and
non-vital components should be disabled; compiler-flags and build-options will
be the primary means of enabling them.
II. Styling
-----------
The source-code in this project is formatted to the "Allman" style of
indentation; see the provided example below:
while (x == y)
{
function();
function_2();
}
Note that braces align with the control statement, and statements placed
within the braces are indented.
Allman-style indentation maximizes the readability of the program and,
via a clear, block-like structure, reduces the probabilty of ambiguous
formatting.
Each source file must have a comment at the bottom marking the end of
its content e.g.
/* --- end of FILE_C --- */
The period located before the extension is shown as an underscore, and
the name is now capitalized, whereas the real filename is snake_case.
--- end of 2.5 LANGUAGE ---

View file

@ -0,0 +1,32 @@
LIBRARIES
=========
Each library used should be widely portbale and should lack
platform-dependent features. Components that are not written in standard
C/C++ or D should be disabled by default at compilation; only being
enabled by flags.
Note: libraries licensed under any version of the GNU GPL should be
avoided, due to the fact that these licenses require that the software
linking them is provided under the same terms. The LGPL is an exception, but
instructions for replacing the library with a different version must be
provided, as the LGPL requires that users can easily modify the LGPL code in
contrast to the common misconception that this license forbids static
linking. In general, copyleft and strongly reciprical licenses must be
avoided.
1.) Libraries should always be included as Git submodules.
2.) Libraries should only be included if writing the same functionality
would take an unreasonably long period of time.
3.) Libraries should be platform-agnostic, or they should at least provide
the ability to replace components with those required on a different system.
4.) All libraries must be disabled by default at compilation and must only
be enabled via compilation options.
Adding on, all contributions must be original and not be derived from
the work of another person, company, software, or any other entity that may
generate the content in question within this document.
Header files should only be used to declare functions.
--- end of 2.7 LIBRARIES ---

File diff suppressed because it is too large Load diff

286
src/filesize/size.c Executable file
View file

@ -0,0 +1,286 @@
/**
* @author : Aidan Mullen (git@acm.contact)
* @file : filesize
* @created : Wednesday Jun 19, 2024 21:10:14 EDT
*/
#include <stdio.h>
#include <string.h>
#include "filesize.h"
/* Test FILENAME_MAX on different platforms. */
char filename[FILENAME_MAX];
char name[FILENAME_MAX];
/*
* ===========
* Buffer Size
* ===========
*
* Buffer size is chosen at compilation; it limits the block-size chosen by the
* user. When the block size is greater than the buffer, overflow occurs.
*
* The buffer size is defined in bytes.
*
* Larger buffer sizes are less accurate, which may be possible to fix if a
* position is set at the end of the read block, then the remaining area is
* read using a smaller buffer size.
*/
/* This buffer size selection should be relegated to the options.ini file. */
#define BUFFER 1073741824
#if !defined(BUFFER) || BUFFER == 1
char buf[1]; /* 1B */
#elif BUFFER == 2
char buf[2]; /* 2B */
#elif BUFFER == 4
char buf[4]; /* 4B */
#elif BUFFER == 8
char buf[8]; /* 8B */
#elif BUFFER == 16
char buf[16]; /* 16B */
#elif BUFFER == 32
char buf[32]; /* 32B */
#elif BUFFER == 64
char buf[64]; /* 64B */
#elif BUFFER == 128
char buf[128]; /* 128B */
#elif BUFFER == 256
char buf[256]; /* 256B */
#elif BUFFER == 512
char buf[512]; /* 512B */
#elif BUFFER == 1024
char buf[1024]; /* 1KB */
#elif BUFFER == 2048
char buf[2048]; /* 2KB */
#elif BUFFER == 4096
char buf[4096]; /* 4KB */
#elif BUFFER == 8192
char buf[8192]; /* 8KB */
#elif BUFFER == 1048576
char buf[1048576]; /* 1MB */
#elif BUFFER == 536870912
char buf[536870912]; /* 512MB */
#elif BUFFER == 1073741824
char buf[1073741824]; /* 1GB */
#else
char buf[BUFFER];
#endif
unsigned long int bsize = BUFFER;
fpos_t pos;
fpos_t end;
/*
* ===============
* Fallback Reader
* ===============
*
* The reader counts each record in the file, then adds the value of the records
* (in bytes) in order to return the filesize.
*
* Fallback function in-case a platform solution is not present.
* Note that, depending on the buffer size, this method may be somewhat
* inaccurate, as a higher buffer size will only measure in records equivalent
* to its value, and may stop before reaching the end of the file; it may be
* possible to account for this by restarting the file-read at the endpoint
* found by fread with a lower buffer size, but this would require that fseek
* and ftell are not used, since these often use signed 32-bit integers that
* limit the maximum size they can read to ~2GB.
*/
int get_size_fallback(void)
{
/*
unsigned long int size = 0;
unsigned long int record = 0;
*/
unsigned long size = 0;
unsigned long record = 0;
FILE * file;
/* If mode is CLI */
printf("Enter a filename: ");
fgets(filename, sizeof(filename), stdin);
/* Compare filename with \r\n and remove them. */
filename[strcspn(filename, "\r\n")] = 0;
strcpy(name, filename);
printf("Reading file \"%s\"...\n", name);
file = fopen(filename, "rb");
printf("Warning: Using fallback reader; process may be slow.\n");
printf("Initial buffer size: %lu\n", bsize);
if (file)
{
fgetpos(file, &pos);
printf("Attempting to read file...\n");
for
(
size = 0;
(fread(buf, sizeof * buf, bsize, file) == bsize);
(record = size)
)
{
(size = size + bsize);
fgetpos(file, &end);
printf("Read: [ %luB ]\n", size);
if (record == size)
{
printf("No appropriately sized blocks remaining.\n");
break;
}
}
/*
* ==============
* Small File Fix
* ==============
*
* If result is 0, try again with lower block size, as small
* files cannot be read when the selected size is larger than them.
*/
record = 0;
if (size == 0)
{
while (bsize > 1)
{
printf("Attempting to read with lower buffer size...\n");
bsize = (bsize/2);
/* bsize = 1; */
fsetpos(file, &pos);
printf("Buffer size lowered to %luB\n", bsize);
while (fread(buf, sizeof * buf, bsize, file) == bsize)
{
size = size + bsize;
fgetpos(file, &pos);
printf("Read: [ %luB ]\n", size);
if (record == size)
{
printf("No appropriately sized blocks remaining.\n");
break;
}
record = size;
}
}
}
/*
* ==============
* Large File Fix
* ==============
*
* Using a large buffer to read large files quickly resulted in an
* inaccurate filesize.
*
* This block lowers the block size at the end of the reading, and
* attempts to read data after the current position in the file. It
* repeats this until the buffer size is one byte.
*
* The accuracy should be around plus-or-minus one byte when reading.
*/
while (size > 0)
{
printf("Checking for remaining data...\n");
bsize = (bsize/2);
fsetpos(file, &end);
while (fread(buf, sizeof * buf, bsize, file) == bsize)
{
size = size + bsize;
fgetpos(file, &end);
printf("Read: [ %luB ]\n", size);
if (record == size)
{
printf("No appropriately sized blocks remaining.\n");
break;
}
record = size;
}
if (bsize > 1)
{
continue;
}
else
{
printf("Buffer at minimum size; stopping.\n");
break;
}
}
printf("No further data to read; stopping.\n");
fclose(file);
printf("Final buffer size: %luB\n", bsize);
printf("\nFilesize: %luB\n", size);
}
else
{
printf("Error: file not found.\n");
}
return(size);
}
/* --- end of SIZE_C --- */

View file

@ -6,7 +6,7 @@ import godot;
import godot.node;
// minimal class example with _ready method that will be invoked on creation
class Greeter : GodotScript!Node {
class init : GodotScript!Node {
@Property String name;
// this method is a special godot entry point when object is added to the scene
@ -23,8 +23,8 @@ mixin GodotNativeLibrary!(
// this is a name prefix of the plugin to be acessible inside godot
// it must match the prefix in .gdextension file:
// entry_symbol = "mydplugin_gdextension_entry"
"mydplugin",
"libsb_init",
// here goes the list of classes you would like to expose in godot
Greeter,
init,
);

102
src/logging/logging.c Executable file
View file

@ -0,0 +1,102 @@
/**
* @author : Aidan Mullen (git@acm.contact)
* @file : logging
* @created : Sunday Mar 24, 2024 10:05:35 EDT
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "logging.h"
#define VERSION "0.1.0-a.1"
#define TIME_BUF 64
char *note; /* Store note for logged actions. */
time_t cur;
/*
* Currently copies version number into the version variable; the version
* number should be stored in a .INI file.
*/
/* TODO: make struct for opening log file and appending. */
/* A new log file should be used for each day. */
/*
* =============
* Log and Print
* =============
*/
void flog(char *note)
{
FILE *logfile = fopen("log", "a");
/*char *timef = ctime(&cur);*/
/*char *timen = strtok(ctime(&cur), "\r\n");*/
char stime[TIME_BUF]; /* Max length of date is 64 by default. */
/* strcspn method to remove new line will not work for some reason. */
time(&cur); /* Store time in cur. */
/* ctime -> time char */
/* Custom time string. */
strftime(stime, TIME_BUF, "[ %a %Y-%m-%d %X ]: ", localtime(&cur));
/*timef[strcspn(timef, "\r\n")] = '\0';*/
/*printf("[ %s ]: %s\n", timef, note);
fprintf(logfile, "[ %s ]: %s\n", timef, note);*/
printf("%s %s\n", stime, note);
fprintf(logfile, "%s %s\n", stime, note);
fclose(logfile);
}
/*
* ========
* Log Only
* ========
*/
void sflog(char *note)
{
FILE *logfile = fopen("log", "a");
/* strcspn method to remove new line will not work for some reason. */
time(&cur); /* Store time in cur. */
/* ctime -> time char */
fprintf(logfile, "[ %s ]: %s\n", ctime(&cur), note);
fclose(logfile);
}
/*
* ==========
* Create Log
* ==========
*/
void init_log(void) /* Will be used for logging in the future. */
{
FILE *logfile = fopen("log", "r");
if (logfile == NULL)
{
printf("Creating new log...\n");
fopen("log", "w");
flog("New log created");
}
flog("Logging started.");
/*flog(strncat("Version: ", VERSION, sizeof(VERSION)));*/
flog(VERSION);
fclose(logfile);
}
/* --- end of LOGGING_C --- */

19
src/logging/logging.h Executable file
View file

@ -0,0 +1,19 @@
/**
* @author : Aidan Mullen (git@acm.contact)
* @file : logging
* @created : Sunday Mar 24, 2024 10:06:11 EDT
*/
#ifndef LOGGING_H
#define LOGGING_H
char get_version(void);
void flog(char *note);
void sflog(char *note);
void init_log(void);
#endif
/* --- end of LOGGING_H --- */