1**nonstd** is a single-header C library providing a collection of "non-standard"
2but highly useful utilities, data structures, and type definitions that are
3often missing from the C standard library. It aims to make C programming more
4ergonomic and productive. It aims to be C99 compliant.
5
6> [!IMPORTANT]
7> There are more involved libraries out there providing better granularity
8> and functionality. This library is intended for ease of use first and
9> foremost. It is not a replacement for those libraries. Use at your own risk.
10
11## Features
12
13- **Shorthand Types**: Concise integer types (`i8`, `u32`, `usize`, etc.) for better readability.
14- **Utility Macros**: Common helpers like `countof`, `MIN`, `MAX`, `CLAMP`, and `static_foreach`.
15- **String View (`stringv`)**: Non-owning, read-only string references to avoid unnecessary copies.
16- **String Builder (`stringb`)**: Growable, mutable string buffer for efficient string construction.
17- **Dynamic Array (`array`)**: Generic growable arrays implemented via macros (similar to `std::vector` in C++).
18- **Slices (`slice`)**: Generic non-owning views into arrays.
19- **Memory Arena**: Simple block-based arena allocator for bulk memory management.
20- **File I/O**: Helper functions to read and write entire files with a single call.
21- **Logging**: Simple, leveled logging with ANSI colors and timestamps.
22- **Canvas & PPM**: Simple 2D drawing API with PPM (ASCII) import/export.
23
24## Installation
25
26`nonstd` is a single-header library. To use it:
27
281. Copy `nonstd.h` into your project's include directory.
292. In **one** C source file, define `NONSTD_IMPLEMENTATION` before including the
30 header to create the implementation:
31
32```c
33#define NONSTD_IMPLEMENTATION
34#include "nonstd.h"
35```
36
373. In other files, just include it normally:
38
39```c
40#include "nonstd.h"
41```
42
43## Usage
44
45Check the `examples` directory for usage examples. But here are a few simple
46examples:
47
48### 1. Basic Types & Macros
49
50```c
51#include "nonstd.h"
52
53void example() {
54 i32 x = 10;
55 u64 y = 2000;
56 usize size = 1024;
57
58 int numbers[] = {1, 2, 3, 4, 5};
59 printf("Count: %zu\n", countof(numbers)); // 5
60
61 int val = CLAMP(100, 0, 10); // 10
62
63 // Static foreach loop
64 int n;
65 static_foreach(int, n, numbers) {
66 printf("%d ", n);
67 }
68}
69```
70
71### 2. Dynamic Arrays
72
73Create type-safe growable arrays for any type.
74
75```c
76// Define an array of integers
77array(int) numbers;
78array_init(numbers);
79
80// Push values
81array_push(numbers, 10);
82array_push(numbers, 20);
83array_push(numbers, 30);
84
85// Iterate (index basic loop or helper macro)
86int val;
87array_foreach(numbers, val) {
88 printf("%d\n", val);
89}
90
91// Access by index
92if (numbers.length > 0) {
93 printf("First: %d\n", numbers.data[0]);
94 // or
95 printf("First: %d\n", array_get(numbers, 0));
96}
97
98// Clean up
99array_free(numbers);
100```
101
102### 3. String Views & Builders
103
104**String View (`stringv`)**:
105Ideal for parsing and passing strings around without allocation.
106
107```c
108const char *raw = "Hello World";
109stringv sv = sv_from_cstr(raw);
110stringv word = sv_slice(sv, 0, 5); // "Hello" (no allocation)
111
112if (sv_starts_with(sv, sv_from_cstr("Hello"))) {
113 // ...
114}
115```
116
117**String Builder (`stringb`)**:
118Efficiently construct strings.
119
120```c
121stringb sb;
122sb_init(&sb, 0); // 0 = default capacity
123
124sb_append_cstr(&sb, "Hello");
125sb_append_char(&sb, ' ');
126sb_append_cstr(&sb, "World");
127
128printf("%s\n", sb.data); // "Hello World"
129
130sb_free(&sb);
131```
132
133### 4. Memory Arena
134
135Efficiently allocate many small objects and free them all at once.
136
137```c
138Arena arena = arena_make();
139
140// Allocations are fast and contiguous within blocks
141void *obj1 = arena_alloc(&arena, 64);
142void *obj2 = arena_alloc(&arena, 128);
143
144// growth is automatic if a block is full
145
146// Free everything at once
147arena_free(&arena);
148```
149
150### 5. File I/O Helpers
151
152Read or write files with a single functional call.
153
154```c
155size_t size;
156char *content = read_entire_file("data.txt", &size);
157
158if (content) {
159 printf("Read %zu bytes:\n%s\n", size, content);
160 free(content); // Standard free (unless using arena)
161}
162
163// Or read directly into a string builder
164stringb file_sb = read_entire_file_sb("config.ini");
165// ... use file_sb ...
166sb_free(&file_sb);
167
168```
169
170### 6. Logging
171
172Simple logging with levels (`ERROR`, `WARN`, `INFO`, `DEBUG`), timestamps, and colors.
173
174```c
175// Set log level (default is INFO)
176set_log_level(LOG_DEBUG);
177
178// Use macros for logging
179LOG_INFO_MSG("Starting application...");
180LOG_DEBUG_MSG("Variable x = %d", 42);
181LOG_WARN_MSG("Low memory warning");
182LOG_ERROR_MSG("Connection failed");
183
184// Environment variable override supported:
185// LOG_LEVEL=0 (ERROR) ... 3 (DEBUG)
186```
187
188### 7. Canvas & PPM Images
189
190Create simple 2D images, draw shapes, and save to PPM (ASCII) format.
191
192```c
193// Initialize a 400x400 canvas
194Canvas canvas = ppm_init(400, 400);
195
196// Use predefined colors or HEX/RGB macros
197ppm_fill(&canvas, COLOR_HEX(0x1a1a1a));
198
199// Draw basic shapes
200ppm_draw_rect(&canvas, 50, 50, 100, 100, COLOR_RED);
201ppm_draw_circle(&canvas, 250, 100, 40, COLOR_BLUE);
202ppm_draw_line(&canvas, 200, 200, 350, 350, COLOR_GREEN);
203ppm_draw_triangle(&canvas, 50, 350, 150, 350, 100, 250, COLOR_YELLOW);
204
205// Save to file
206if (ppm_save(&canvas, "output.ppm")) {
207 printf("Image saved successfully!\n");
208}
209
210// Clean up
211ppm_free(&canvas);
212```
213
214## Testing
215
216The project includes a test suite using `minunit`.
217
218To build and run the tests:
219
220```bash
221make test
222```
223
224## Acknowledgments
225
226- https://github.com/tsoding/nob.h