The Fossil I/O Input API provides a secure, context-aware layer for reading, validating, and sanitizing user input on top of the Fossil file stream system. It unifies low-level character and line-based input with higher-level validation utilities for numbers, emails, passwords, and bot detection, while offering robust sanitization through context-specific rules (HTML, SQL, shell, filenames, and more). By returning detailed bitmask flags describing detected risks, the API enables applications to make informed security decisions without sacrificing usability. The accompanying C++ wrapper preserves the C API’s determinism while adding ergonomic helpers, std::string integration, and safer defaults for modern applications.
Code reference for C and C++ APIs for the respective Fossil Logic library.
HEADER REFERENCE #
#ifndef FOSSIL_IO_INPUT_H
#define FOSSIL_IO_INPUT_H
#include <stdarg.h>
#include "file.h"
/* Contexts */
typedef enum {
FOSSIL_CTX_GENERIC,
FOSSIL_CTX_HTML,
FOSSIL_CTX_SQL,
FOSSIL_CTX_SHELL,
FOSSIL_CTX_FILENAME,
FOSSIL_CTX_NONE
} fossil_context_t;
/* Bitmask flags for string sanitization results */
#define FOSSIL_SAN_OK 0x00 /* No issues detected; string is clean */
#define FOSSIL_SAN_MODIFIED 0x01 /* Input was modified during sanitization */
#define FOSSIL_SAN_SCRIPT 0x02 /* Script or JavaScript patterns detected */
#define FOSSIL_SAN_SQL 0x04 /* SQL injection patterns detected */
#define FOSSIL_SAN_SHELL 0x08 /* Shell or command execution patterns detected */
#define FOSSIL_SAN_BASE64 0x10 /* Suspiciously long base64 sequences detected */
#define FOSSIL_SAN_PATH 0x20 /* Path traversal or filesystem patterns detected */
#define FOSSIL_SAN_BOT 0x40 /* Bot or automated agent patterns detected */
#define FOSSIL_SAN_SPAM 0x80 /* Spam or suspicious marketing content detected */
#ifdef __cplusplus
extern "C" {
#endif
/**
* Reads a single character from the input stream.
*
* @param input_stream Pointer to the input stream to read from.
* @return The character read as an unsigned char cast to an int, or EOF on end-of-file or error.
*/
int fossil_io_getc(fossil_io_file_t *input_stream);
/**
* @brief Trim leading and trailing whitespace from a string in place.
*
* This function removes all whitespace characters (spaces, tabs, newlines, etc.)
* from the beginning and end of the input string. The trimming is done **in place**,
* modifying the original string, and the result is always null-terminated.
*
* @param str Pointer to the null-terminated string to be trimmed.
* Must not be NULL. If the string is empty or contains only whitespace,
* it will be converted to an empty string ("").
*
* @note This function does not allocate memory; it simply shifts characters within
* the existing string buffer. The caller is responsible for ensuring that
* the buffer is writable and large enough to hold the original string.
*
* @example
* char s[] = " hello world \n";
* fossil_io_trim(s);
* // s now contains "hello world"
*/
void fossil_io_trim(char *str);
/**
* Reads a line from the input stream and stores it into the buffer pointed to by 'buf'.
*
* @param buf Pointer to the buffer where the line will be stored.
* @param size Maximum number of characters to be read, including the null terminator.
* @param input_stream Pointer to the input stream to read from.
* @return On success, the function returns 'buf'. If the end-of-file is reached or an error occurs, it returns NULL.
*/
char *fossil_io_gets_from_stream(char *buf, size_t size, fossil_io_file_t *input_stream);
/**
* Reads a line from the input stream with error reporting.
*
* @param buf Pointer to the buffer where the line will be stored.
* @param size Maximum number of characters to be read, including the null terminator.
* @param input_stream Pointer to the input stream to read from.
* @param error_code Pointer to an integer to store the error code (e.g., EOF, input error).
* @return On success, the function returns 'buf'. If the end-of-file is reached or an error occurs, it returns NULL.
*/
char *fossil_io_gets_from_stream_ex(char *buf, size_t size, fossil_io_file_t *input_stream, int *error_code);
/**
* Reads formatted input from the standard input stream.
*
* @param format The format string specifying how the input should be interpreted.
* @param ... Additional arguments for storing the input values.
* @return On success, the number of input items successfully matched and assigned is returned.
* On failure, EOF is returned.
*/
int fossil_io_scanf(const char *format, ...);
/**
* Reads formatted input from the specified input stream.
*
* @param input_stream Pointer to the input stream to read from.
* @param format The format string specifying how the input should be interpreted.
* @param ... Additional arguments for storing the input values.
* @return On success, the number of input items successfully matched and assigned is returned.
* On failure, EOF is returned.
*/
int fossil_io_fscanf(fossil_io_file_t *input_stream, const char *format, ...);
/**
* Validates the input buffer and size before reading.
*
* @param buf Pointer to the buffer where the input will be stored.
* @param size Size of the buffer.
* @return 1 if the buffer and size are valid; 0 otherwise.
*/
int fossil_io_validate_input_buffer(const char *buf, size_t size);
/**
* Reads a UTF-8 encoded line from the input stream.
*
* @param buf Pointer to the buffer where the line will be stored.
* @param size Maximum number of characters to be read, including the null terminator.
* @param input_stream Pointer to the input stream to read from.
* @return On success, the function returns 'buf'. If the end-of-file is reached or an error occurs, it returns NULL.
*/
char *fossil_io_gets_utf8(char *buf, size_t size, fossil_io_file_t *input_stream);
/**
* @brief Validates if the input string is a valid integer.
*
* @param input The input string to validate.
* @param output Pointer to an integer where the parsed value will be stored if valid.
* @return true if the input is a valid integer, false otherwise.
*/
int fossil_io_validate_is_int(const char *input, int *output);
/**
* @brief Validates if the input string is a valid float.
*
* @param input The input string to validate.
* @param output Pointer to a float where the parsed value will be stored if valid.
* @return true if the input is a valid float, false otherwise.
*/
int fossil_io_validate_is_float(const char *input, float *output);
/**
* @brief Validates if the input string contains only alphanumeric characters.
*
* @param input The input string to validate.
* @return true if the input is alphanumeric, false otherwise.
*/
int fossil_io_validate_is_alnum(const char *input);
/**
* @brief Validates if the input string is a valid email address.
*
* @param input The input string to validate.
* @return true if the input is a valid email address, false otherwise.
*/
int fossil_io_validate_is_email(const char *input);
/**
* @brief Validates if the input string does not exceed the specified maximum length.
*
* @param input The input string to validate.
* @param max_length The maximum allowed length of the input string.
* @return true if the input length is within the specified limit, false otherwise.
*/
int fossil_io_validate_is_length(const char *input, size_t max_length);
/**
* Check if password is weak or bad.
*
* Returns:
* 1 if password is weak/bad
* 0 if password passes the basic checks
*/
int fossil_io_validate_is_weak_password(const char *password,
const char *username,
const char *email);
/**
* Check if a user-agent string looks like a bot/crawler
*/
int fossil_io_validate_is_suspicious_bot(const char *input);
/**
* Check if an email belongs to a disposable / suspicious domain
*/
int fossil_io_validate_is_disposable_email(const char *input);
/**
* Check if a string looks like a bot-style username:
* - Too many digits in a row
* - High ratio of digits to letters
* - Contains suspicious words like "bot", "test", "fake"
* - Looks like random noise (entropy check)
*/
int fossil_io_validate_is_suspicious_user(const char *input);
/**
* @brief Validate and sanitize a string according to a specified context.
*
* This function scans the input string for suspicious content (scripts, SQL injection,
* shell commands, bots, spam, path traversal, or long base64 blobs) and performs
* context-aware sanitization by replacing disallowed characters with underscores.
* It also returns a bitmask indicating the types of issues detected.
*
* @param input The input string to be validated and sanitized. Must not be NULL.
* @param output The buffer to receive the sanitized string. Must not be NULL.
* @param output_size The size of the output buffer. Must be greater than 0.
* @param ctx The context in which the string will be used, which determines
* the allowed character set and stricter rules for certain contexts.
*
* @return Bitmask of flags indicating results:
* - FOSSIL_SAN_OK (0x00): No issues detected; string is clean.
* - FOSSIL_SAN_MODIFIED (0x01): Input was modified during sanitization.
* - FOSSIL_SAN_SCRIPT (0x02): Script or JavaScript patterns detected.
* - FOSSIL_SAN_SQL (0x04): SQL injection patterns detected.
* - FOSSIL_SAN_SHELL (0x08): Shell or command execution patterns detected.
* - FOSSIL_SAN_BASE64 (0x10): Suspiciously long base64 sequences detected.
* - FOSSIL_SAN_PATH (0x20): Path traversal or filesystem patterns detected.
* - FOSSIL_SAN_BOT (0x40): Bot or automated agent patterns detected.
* - FOSSIL_SAN_SPAM (0x80): Spam or suspicious marketing content detected.
*
* @note The sanitized output is always null-terminated and will not exceed
* output_size bytes. The function uses heuristics and is not a substitute
* for context-specific escaping or prepared statements in SQL/HTML.
*/
int fossil_io_validate_sanitize_string(const char *input,
char *output,
size_t output_size,
fossil_context_t ctx);
/**
* Displays a menu of choices and returns the selected choice.
*
* @param prompt The prompt message before displaying the menu.
* @param choices Array of strings representing the choices.
* @param num_choices The number of choices.
* @return The index of the selected choice.
*/
int fossil_io_display_menu(const char *prompt, const char *choices[], int num_choices);
/**
* Displays a simple progress bar.
*
* @param progress The current progress (0-100).
*/
void fossil_io_show_progress(int progress);
/**
* @brief Reads a line of input from standard input into the provided buffer.
*
* Reads at most `size - 1` characters from `stdin` and stores them in `buffer`.
* If a newline character is read, it is replaced with a null terminator.
*
* @param buffer Pointer to the character buffer where input will be stored.
* @param size The size of the buffer.
* @return 0 on success, -1 on error or end-of-file.
*/
int fossil_io_gets(char *buffer, size_t size);
#ifdef __cplusplus
}
#include <cstddef>
#include <string>
#include <vector>
#include <utility>
#include <cstdarg>
#include <istream>
/**
* Namespace for the Fossil Logic I/O library.
*/
namespace fossil {
/**
* Namespace for the I/O utilities.
*/
namespace io {
/**
* Class for handling input operations.
*/
class Input {
public:
/**
* Reads a single character from the input stream.
*
* @param input_stream Pointer to the input stream to read from.
* @return The character read as an unsigned char cast to an int, or EOF on end-of-file or error.
*/
static int getc(fossil_io_file_t *input_stream) {
return fossil_io_getc(input_stream);
}
/**
* @brief Trim leading and trailing whitespace from a string in place.
*
* This function removes all whitespace characters (spaces, tabs, newlines, etc.)
* from the beginning and end of the input string. The trimming is done **in place**,
* modifying the original string, and the result is always null-terminated.
*
* @param str Pointer to the null-terminated string to be trimmed.
* Must not be NULL. If the string is empty or contains only whitespace,
* it will be converted to an empty string ("").
*
* @note This function does not allocate memory; it simply shifts characters within
* the existing string buffer. The caller is responsible for ensuring that
* the buffer is writable and large enough to hold the original string.
*
* @example
* char s[] = " hello world \n";
* fossil_io_trim(s);
* // s now contains "hello world"
*/
static void trim(char *str) {
fossil_io_trim(str);
}
/**
* Reads a line from the input stream and stores it into the buffer pointed to by 'buf'.
*
* @param buf Pointer to the buffer where the line will be stored.
* @param size Maximum number of characters to be read, including the null terminator.
* @param input_stream Pointer to the input stream to read from.
* @return On success, the function returns 'buf'. If the end-of-file is reached or an error occurs, it returns NULL.
*/
static char *gets_from_stream(char *buf, size_t size, fossil_io_file_t *input_stream) {
return fossil_io_gets_from_stream(buf, size, input_stream);
}
/**
* Reads a line from the input stream with error reporting.
*
* @param buf Pointer to the buffer where the line will be stored.
* @param size Maximum number of characters to be read, including the null terminator.
* @param input_stream Pointer to the input stream to read from.
* @param error_code Pointer to an integer to store the error code (e.g., EOF, input error).
* @return On success, the function returns 'buf'. If the end-of-file is reached or an error occurs, it returns NULL.
*/
static char *gets_from_stream_ex(char *buf, size_t size, fossil_io_file_t *input_stream, int *error_code) {
return fossil_io_gets_from_stream_ex(buf, size, input_stream, error_code);
}
/**
* Validates the input buffer and size before reading.
*
* @param buf Pointer to the buffer where the input will be stored.
* @param size Size of the buffer.
* @return 1 if the buffer and size are valid; 0 otherwise.
*/
static int validate_input_buffer(const char *buf, size_t size) {
return fossil_io_validate_input_buffer(buf, size);
}
/**
* Reads a UTF-8 encoded line from the input stream.
*
* @param buf Pointer to the buffer where the line will be stored.
* @param size Maximum number of characters to be read, including the null terminator.
* @param input_stream Pointer to the input stream to read from.
* @return On success, the function returns 'buf'. If the end-of-file is reached or an error occurs, it returns NULL.
*/
static char *gets_utf8(char *buf, size_t size, fossil_io_file_t *input_stream) {
return fossil_io_gets_utf8(buf, size, input_stream);
}
/**
* Reads a line of input from standard input into the provided buffer.
*
* Reads at most `size - 1` characters from `stdin` and stores them in `buffer`.
* If a newline character is read, it is replaced with a null terminator.
*
* @param buffer Pointer to the character buffer where input will be stored.
* @param size The size of the buffer.
* @return 0 on success, -1 on error or end-of-file.
*/
int gets(char *buffer, size_t size) {
return fossil_io_gets(buffer, size);
}
/**
* Reads formatted input from the standard input stream.
*
* @param format The format string specifying how the input should be interpreted.
* @param ... Additional arguments for storing the input values.
* @return On success, the number of input items successfully matched and assigned is returned.
* On failure, EOF is returned.
*/
static int scanf(const char *format, ...) {
va_list args;
va_start(args, format);
int result = fossil_io_scanf(format, args);
va_end(args);
return result;
}
/**
* Reads formatted input from the specified input stream.
*
* @param input_stream Pointer to the input stream to read from.
* @param format The format string specifying how the input should be interpreted.
* @param ... Additional arguments for storing the input values.
* @return On success, the number of input items successfully matched and assigned is returned.
* On failure, EOF is returned.
*/
static int fscanf(fossil_io_file_t *input_stream, const char *format, ...) {
va_list args;
va_start(args, format);
int result = fossil_io_fscanf(input_stream, format, args);
va_end(args);
return result;
}
/**
* @brief Validates if the input string is a valid integer.
*
* @param input The input string to validate.
* @param output Pointer to an integer where the parsed value will be stored if valid.
* @return true if the input is a valid integer, false otherwise.
*/
static int validate_is_int(const char *input, int *output) {
return fossil_io_validate_is_int(input, output);
}
/**
* @brief Validates if the input string is a valid float.
*
* @param input The input string to validate.
* @param output Pointer to a float where the parsed value will be stored if valid.
* @return true if the input is a valid float, false otherwise.
*/
static int validate_is_float(const char *input, float *output) {
return fossil_io_validate_is_float(input, output);
}
/**
* @brief Validates if the input string contains only alphanumeric characters.
*
* @param input The input string to validate.
* @return true if the input is alphanumeric, false otherwise.
*/
static int validate_is_alnum(const char *input) {
return fossil_io_validate_is_alnum(input);
}
/**
* @brief Validates if the input string is a valid email address.
*
* @param input The input string to validate.
* @return true if the input is a valid email address, false otherwise.
*/
static int validate_is_email(const char *input) {
return fossil_io_validate_is_email(input);
}
/**
* @brief Validates if the input string does not exceed the specified maximum length.
*
* @param input The input string to validate.
* @param max_length The maximum allowed length of the input string.
* @return true if the input length is within the specified limit, false otherwise.
*/
static int validate_is_length(const char *input, size_t max_length) {
return fossil_io_validate_is_length(input, max_length);
}
/**
* Check if password is weak or bad.
* Returns true if weak/bad, false otherwise.
*/
static bool is_weak_password(const std::string &password,
const std::string &username = "",
const std::string &email = "") {
return fossil_io_validate_is_weak_password(
password.c_str(),
username.empty() ? nullptr : username.c_str(),
email.empty() ? nullptr : email.c_str()) != 0;
}
/**
* Check if a user-agent string looks like a bot/crawler
*/
static bool is_suspicious_bot(const std::string &userAgent) {
return fossil_io_validate_is_suspicious_bot(userAgent.c_str()) != 0;
}
/**
* Check if an email belongs to a disposable / suspicious domain
*/
static bool is_disposable_email(const std::string &email) {
return fossil_io_validate_is_disposable_email(email.c_str()) != 0;
}
/**
* Check if a string looks like a bot-style username
*/
static bool is_suspicious_user(const std::string &username) {
return fossil_io_validate_is_suspicious_user(username.c_str()) != 0;
}
/**
* Sanitize a string according to context.
* Returns the bitmask flags from the sanitizer.
*/
static int validate_sanitize_string(std::string &input, fossil_context_t ctx) {
std::vector<char> buffer(input.size() + 1);
int flags = fossil_io_validate_sanitize_string(
input.c_str(),
buffer.data(),
buffer.size(),
ctx
);
input.assign(buffer.data());
return flags;
}
/**
* @brief Displays a menu of choices and returns the selected choice.
*
* @param prompt The prompt message before displaying the menu.
* @param choices Array of strings representing the choices.
* @param num_choices The number of choices.
* @return The index of the selected choice.
*/
static int display_menu(const char *prompt, const char *choices[], int num_choices) {
return fossil_io_display_menu(prompt, choices, num_choices);
}
/**
* @brief Displays a simple progress bar.
*
* @param progress The current progress (0-100).
*/
static void show_progress(int progress) {
fossil_io_show_progress(progress);
}
/**
* @brief Overloads the input stream operator for the Input class.
*
* @param input_stream The input stream to read from.
* @param input The Input object to populate.
* @return The input stream after reading.
*/
friend std::istream &operator>>(std::istream &input_stream, Input & /*input*/) {
// Implement the logic for populating the Input object from the input stream.
// This is a placeholder implementation.
char buffer[256];
input_stream.getline(buffer, sizeof(buffer));
// Process the buffer as needed to populate the Input object.
return input_stream;
}
};
}
}
#endif
#endif /* FOSSIL_IO_FRAMEWORK_H */SAMPLE CODE C #
#include "fossil/io/input.h"
#include <stdio.h>
#include <string.h>
int main(void) {
char input[256];
char sanitized[256];
printf("Enter a username: ");
if (fossil_io_gets(input, sizeof(input)) != 0) {
fprintf(stderr, "Input error\n");
return 1;
}
/* Trim whitespace */
fossil_io_trim(input);
/* Sanitize for filename / identifier context */
int flags = fossil_io_validate_sanitize_string(
input,
sanitized,
sizeof(sanitized),
FOSSIL_CTX_FILENAME
);
if (flags != FOSSIL_SAN_OK) {
printf("Input sanitized (flags=0x%x)\n", flags);
}
/* Validate constraints */
if (!fossil_io_validate_is_length(sanitized, 32) ||
!fossil_io_validate_is_alnum(sanitized)) {
fprintf(stderr, "Invalid username format\n");
return 1;
}
printf("Accepted username: %s\n", sanitized);
return 0;
}SAMPLE CODE C++ #
#include "fossil/io/input.h"
#include <iostream>
#include <string>
int main() {
std::string email;
std::cout << "Enter email address: ";
std::getline(std::cin, email);
/* Sanitize for generic text usage */
int flags = fossil::io::Input::validate_sanitize_string(
email,
FOSSIL_CTX_GENERIC
);
if (flags & FOSSIL_SAN_SCRIPT) {
std::cout << "Warning: script-like content detected\n";
}
if (!fossil::io::Input::validate_is_email(email.c_str())) {
std::cerr << "Invalid email address\n";
return 1;
}
if (fossil::io::Input::is_disposable_email(email)) {
std::cerr << "Disposable email domains are not allowed\n";
return 1;
}
std::cout << "Email accepted: " << email << "\n";
return 0;
}