// Guide for sp.h, a single-header C standard library replacement. You must use this guide when using or discussing sp.h in any capacity.
| name | sp |
| description | Guide for sp.h, a single-header C standard library replacement. You must use this guide when using or discussing sp.h in any capacity. |
| license | MIT |
sp.h, you MUST provide a matching declaration from references/index.md. Function names without the full declaration are COMPLETELY useless, and WILL NOT be tolerated.
user: How do I use the asset registry from sp.h? assistant: [Reads the index, uses the Task tool to search through sources bundled with skill (sp.h, spn.c), includes "sp_str_t sp_str_sub(sp_str_t str, s32 index, s32 len)" in answer] user: Write a function that reads a file and logs its contends assistant: [Searches through bundled source code with Task tool to find relevant APIs and writes function]
references/index.md before trying to search through the codebase. Do not guess; refer to references/index.md to find a precise search term.
user: How do I read a file in sp.h? assistant: [Reads index.md, searches through sp.h and spn.c with Task tool, provides concise, annotated answer]
references/sp.h judiciously as needed; do not guess symbol names, function signatures, or implementation details. Read the source code.SP_APIsp_ and suffixed with _tmalloc, calloc, or realloc; use sp_alloc (which zero initializes)const char*; use sp_str_t (pointer + length)strcmp, strlen, or any string.h functions with sp_str_t; use sp_str_*strcmp, strlen, or any string.h functions with const char*; use sp_cstr_*SP_ZERO_INITIALIZE(). When you need a type, use SP_ZERO_STRUCT(T)sp_da(T) and sp_ht(T) for dynamic arrays and hash maps (sp_dyn_array_* and sp_ht_*)sp_dyn_array_for(arr, it) and sp_ht_for(ht, it) to iterate sp_da and sp_htstr.len > 0; always use !sp_str_empty(str)s32, u8, c8, const c8*)printf family; always use SP_LOG()sp_carr_for() when iterating a C arraydefault is not.Use these when searching through references/index.md, references/sp.h, or references/spn.c
sp_alloc, sp_context, sp_allocator, sp_ossp_str, sp_str_builder, sp_cstrsp_dyn_array / sp_da, sp_ht, sp_rbsp_iosp_pssp_ossp_ossp_tmsp_thread, sp_mutex, sp_semaphore, sp_atomic, sp_spin_locksp_format, SP_LOG, SP_FMT_*// Always zero-initialize structs
sp_str_builder_t builder = SP_ZERO_INITIALIZE();
sp_dynamic_array_t arr = SP_ZERO_INITIALIZE();
// Create strings
sp_str_t literal = sp_str_lit("hello"); // Compile-time string literal
sp_str_t view = sp_str_view(some_char_ptr); // Runtime C string (calculates length)
sp_str_t copy = sp_str_from_cstr("hello"); // Allocates and copies
const char* cstr = sp_str_to_cstr(str);
sp_dyn_array(int) numbers = SP_NULLPTR;
sp_dyn_array_push(numbers, 42);
sp_dyn_array_push(numbers, 100);
sp_dyn_array_for(numbers, i) {
SP_LOG("numbers[{}] = {}", SP_FMT_U32(i), SP_FMT_S32(numbers[i]));
}
u32 count = sp_dyn_array_size(numbers);
u32 capacity = sp_dyn_array_capacity(numbers);
// Cleanup happens automatically via allocator
sp_ht(s32, s32) hta = SP_NULLPTR;
sp_ht(sp_str_t, s32) htb = SP_NULLPTR;
sp_ht_set_fns(hta, sp_ht_on_hash_str_key, sp_ht_on_compare_str_key);
sp_ht_insert(htb, SP_LIT("answer"), 42);
s32* value_ptr = sp_ht_getp(htb, SP_LIT("answer"));
sp_ht_key_exists(htb, SP_LIT("answer"));
sp_ht_for(htb, it) {
sp_str_t* key = sp_ht_it_getkp(map, it);
s32* val = sp_ht_it_getp(map, it);
}
// Cleanup happens automatically via allocator
// Type-safe formatting with color support
SP_LOG(
"Processing {:fg cyan} with {} {}",
SP_FMT_STR(name),
SP_FMT_U32(count),
SP_FMT_CSTR("items")
);
sp_str_t msg = sp_format("Result: {}", SP_FMT_S32(42));
// Colors: :fg, :bg, :color
// Colors: black, red, green, yellow, blue, magenta, cyan, white
// Add 'bright' prefix for bright variants
// Always use braces, always handle all cases
switch (state) {
case STATE_IDLE: {
break;
}
case STATE_RUNNING: {
break;
}
default: {
SP_UNREACHABLE_CASE();
}
}
// Return an enum for recoverable errors (consumer app may have their own error type)
sp_err_t load_config(sp_str_t path, config_t* config) {
if (!sp_os_does_path_exist(path)) {
SP_LOG("Config not found: {}", SP_FMT_STR(path));
return SP_ERR_WHATEVER;
}
return SP_ERR_OK;
}
// Prefer to SP_ASSERT when possible
void process_array(int* arr, u32 size) {
SP_ASSERT(arr);
SP_ASSERT(size > 0);
}
// SP_FATAL is SP_LOG + SP_ASSERT(false)
if (critical_failure) {
SP_FATAL("Cannot continue: {:fg red}", SP_FMT_STR(reason));
}