Read a regular, seekable file into memory. These functions use fseek/ftell, so pipes and other non-seekable paths are not supported.
LfLines holds a table of line or split pieces. The delimiter is a whole string. Empty tokens are kept, and the source string is not modified. heap is 1 when the table was allocated with malloc; call inp_lines_free to release it.
*_arena variants allocate from an ArenaAllocator. heap is then 0, and inp_lines_free only zeros the struct. Do not call free on arena results.
inp_get_lines strips a trailing \r from each line so \r\n and \n both work. Bare \r is not treated as a line break. An empty file succeeds with n == 0. A missing file returns -1.
Structs
typedef struct {
char *base;
char **lines;
size_t n;
int heap;
} LfLines;
Functions
inp_get_binary
Reads a file at path and returns the contents as an unsigned char * buffer. fsz receives the length. fsz must not be NULL. An empty file returns a non-NULL buffer with *fsz == 0. A missing file returns NULL. The caller frees the buffer.
unsigned char *inp_get_binary(const char *path, size_t *fsz);
unsigned char *inp_get_binary_arena(ArenaAllocator *arena, const char *path,
size_t *fsz);
/* Usage */
size_t fsz = 0;
unsigned char *buf = inp_get_binary("data.bin", &fsz);
free(buf);
inp_get_input
Reads a file at path and returns the contents as a single NUL-terminated string. The caller frees it. Missing file returns NULL.
char *inp_get_input(const char *path);
char *inp_get_input_arena(ArenaAllocator *arena, const char *path);
/* Usage */
char *str = inp_get_input("data.txt");
free(str);
inp_get_lines
Reads a regular file at path and splits on \n into out. Trailing \r is stripped. A trailing newline does not produce an extra empty line; blank lines in the middle are kept. Returns 0 on success, including an empty file (out->n == 0). Returns -1 on error (NULL arguments, missing file, I/O). Do not destroy out on failure.
int inp_get_lines(const char *path, LfLines *out);
int inp_get_lines_arena(ArenaAllocator *arena, const char *path, LfLines *out);
/* Usage */
LfLines lines;
if (inp_get_lines("data.txt", &lines) == 0) {
for (size_t i = 0; i < lines.n; i++) {
printf("%s\n", lines.lines[i]);
}
inp_lines_free(&lines);
}
inp_lines_free
Frees a heap-allocated table (heap == 1) and zeros the struct. Safe on NULL. Use this after inp_get_lines and inp_split. Arena-backed results have heap == 0 and need no free.
void inp_lines_free(LfLines *lines);
inp_get_ints
Reads a newline-separated list of integers. The caller frees the returned array with free(). sz receives the count. Returns NULL if path or sz is NULL, the file is missing, or a line is not an integer. An empty file returns a freeable pointer with *sz == 0.
int *inp_get_ints(const char *path, size_t *sz);
int *inp_get_ints_arena(ArenaAllocator *arena, const char *path, size_t *sz);
/* Usage */
size_t sz = 0;
int *nums = inp_get_ints("nums.txt", &sz);
for (size_t i = 0; i < sz; i++) {
printf("%d\n", nums[i]);
}
free(nums);
inp_split
Splits s on the string delimiter delim. Does not modify s. Empty tokens are kept ("a,,b" split on "," is three parts). Returns 0 on success, -1 on error.
int inp_split(const char *s, const char *delim, LfLines *out);
int inp_split_arena(ArenaAllocator *arena, const char *s, const char *delim,
LfLines *out);
/* Usage */
LfLines sp;
inp_split("Split on whitespace", " ", &sp);
printf("%s\n", sp.lines[0]); /* Prints "Split" */
inp_lines_free(&sp);
Process helpers (lf_capture_system) live in [[process]], not this header.