Lion’s Standard (LS) libraries is a collection of header-only ANSI C (C89) libraries.
These aim to be:
All of these libraries are MIT licensed.
Container libraries use macros to generate type-specific implementations. All generated code is macro-free. LS libraries support custom allocators and handle allocation failures gracefully (where applicable).
A dynamic array (vector).
Example usage:
LS_VEC_INLINE(int, int_vector)
// somewhere in the same file
int_vector vec;
int_vector_init(&vec);
int_vector_push(&vec, 42);
// use vec.data, vec.size, etc.
int_vector_free(&vec);A static (non-allocating) queue.
Example usage:
LS_QUEUE_INLINE(int, int_queue, 32)
// somewhere in the same file
int_queue q;
int_queue_init(&q);
int_queue_push(&q, 42);
int val;
if (int_queue_pop(&q, &val)) {
// do something with val
}A command-line argument parser. Single header, fully ANSI C compliant and unit-tested.
Example usage:
#define LS_ARGS_IMPLEMENTATION
#include "ls_args.h"
// ...
ls_args args;
ls_args_init(&args);
args.help_description = "My program description.";
int verbose = 0;
ls_args_bool(&args, &verbose, "v", "verbose", "Enable verbose output", 0);
const char* output = NULL;
ls_args_string(&args, &output, "o", "output", "Output file", 0);
const char* input;
ls_args_pos_string(&args, &input, "Input file", LS_ARGS_REQUIRED);
if (!ls_args_parse(&args, argc, argv)) {
fprintf(stderr, "%s\n", args.last_error);
// maybe also print help
fprintf(stderr, "%s", ls_args_help(&args));
exit(1);
}
// use verbose, output, input...
ls_args_free(&args);A minimal unit testing framework.
Example usage:
#define LS_TEST_IMPLEMENTATION
#include "ls_test.h"
TEST_CASE(test_add) {
ASSERT_EQ(add(1, 2), 3, "%d");
return 0;
}
TEST_MAINAI usage notice: The extent to which AI/LLMs are used in the development and maintenance of these libraries is documented here.
The following are some rules for all contributed code.
The LibLS namespacing rules are:
The public API must be prefixed with the header name,
e.g. ls_args.h must only expose public API which is
prefixed with ls_args_ or LS_ARGS_, and the
literal library name ls_args might also be used (e.g. for a
struct).
All private
code must be static where possible, and be
prefixed with either the header name like (ls_args_...) or
the underscore-prefixed version (_ls_args_...),
or, more commonly, the short version _lsa_
or lsa_ (e.g. _lst_... for
ls_test, etc).
Public code generated by a library, e.g. LS_VEC_DECL
does not fall under this requirement. For example
LS_VEC_INLINE(int, myvec) can declare types and functions
named myvec or myvec_. Private code generated
should still follow the namespacing rules.
Use the provided .clang-format format and generally
follow the format of surrounding code.
A couple rules:
-NDEBUG).-NDEBUG except those testing
for abort().All AI use must fit within the AI use page, or the page must be adjusted.
The below are ramblings about LibLS. All useful documentation is found in the headers of each library, and nowhere else.
If the same requirement can be fulfilled by two solutions, prefer the simpler one.
LS libraries are written in adherance to this ethos; they must be complete (fulfill the expectations/requirements), but the code must be reasonably terse. Simple code also means minimized dependencies and abstractions. This means LibLS libraries avoid all libraries beyond a subset of the C standard library.
Does this result in NIH syndrome
issues, of re-implementing a
subset of common and well-tested libraries? Yes, however, with the
strong focus on high- or full-branch coverage testing, in a language as
terse as C89 (ANSI C
), common NIH issues are avoided.
Further, LibLS libraries only expose the necessary API and are properly namespaced.