Story
Cori is a single-file C library designed to simplify the process of getting user input in C programs. It provides a comprehensive set of functions that handle common input scenarios and potential errors, allowing programmers to focus more on their program’s logic rather than the intricacies of input handling. Additionally, Cori aims to serve as a safer and more user-friendly replacement for the scanf function, which is often misused by beginners and can easily lead to undefined behavior[1].
Problems Cori intends to solve
Simplify user input handling: Cori provides a set of functions that handle various types of user input, making it easier for programmers to collect and process input without worrying about the underlying complexities.
Replace
scanf: Thescanffunction is notoriously difficult to use correctly, especially for beginners. Cori offers a safer and more intuitive alternative, reducing the risk of undefined behavior and making input handling more straightforward.
Core concepts
Types of input
Cori supports a wide range of input types, each represented by a specific C type:
Signed integers:
intmax,longlong,long,int,shortUnsigned integers:
uintmax,ulonglong,ulong,uint,ushortFloating point numbers:
longdouble,double,floatText:
character,until,line,linelOther:
boolean
Error handling system
Cori includes a robust error handling system that allows programmers to define custom error handlers. The library defines an enumeration InputError that represents all possible error conditions, such as empty input, end-of-file (EOF), invalid boolean characters, multiple characters, not a number, number out of bounds, out of memory, and unsupported numeric base.
Function families
For each type of input, Cori provides a family of functions to handle different scenarios:
read_<typename>: Reads input fromstdinand handles errors using a NO-OP (no operation) error handler.read_<typename>_or: Reads input fromstdinand handles errors using a specified error handler.read_<typename>_from: Reads input from a specifiedFILE *stream and handles errors using a NO-OP error handler.read_<typename>_or_from: Reads input from a specifiedFILE *stream and handles errors using a specified error handler.tryRead_<typename>: Reads input fromstdinonce and returns an error code if an error occurs.tryRead_<typename>_from: Reads input from a specifiedFILE *stream once and returns an error code if an error occurs.
Techniques and patterns used
STB-Style Libraries
Cori is designed as an STB-style library[2], which means it consists of a single header file that contains both the interface and the implementation. This makes it easy to share and reuse, as users only need to include the header file in their projects. However, this approach can lead to large header files, so it is best suited for simple, single-purpose libraries like Cori.
Heavy usage of macros
Cori makes extensive use of macros for metaprogramming, allowing for the generation of repetitive code patterns. One notable pattern used is the X-macro pattern[3], which enables the definition of a set of related functions and data structures in a concise and maintainable way. This approach reduces code duplication and makes the library more flexible and easier to extend.
Example
Cori is designed with simplicity in mind.
#define CORI_IMPLEMENTATION
#include "stb_cori.h"
int main() {
int result;
printf("Type an integer: ");
result = read_int();
printf("Recieved %d\\n", result);
}Conclusion
Cori is a powerful and user-friendly library for handling console input in C programs. By providing a comprehensive set of functions and a robust error handling system, Cori simplifies the input handling process and offers a safer alternative to the scanf function. Its design as an STB-style library and the use of advanced macro techniques make it easy to integrate and extend, making it an excellent choice for both beginners and experienced C programmers, specifically for simple, quick programs
For more details on how to use Cori, please refer to the README file.