This project has been created as part of the 42 curriculum by gastesan.
After evaluation, I refactored this project and integrated it into my libft as a separator-agnostic
get_next_chunk()function.
You can find the detailed Doxygen documentation here
- π Description
- π Instructions
- π§ Technical Choices
- π§© Algorithm explanation
- π Resources
- π€ AI usage notice
get_next_line is an implementation of a line-by-line reader for file descriptors (fd).
Its goal is to provide a reliable, stateful, and norm-compliant function capable of returning one line per call while handling arbitrary buffer sizes and multiple file descriptors (bonus).
This project explores static storage, controlled memory management, and iterative parsing of streamed input.
.
βββ README.md
βββ main.c # Only for tests
βββ file.txt # Only for tests
βββ get_next_line.h
βββ get_next_line.c
βββ get_next_line_bonus.h
βββ get_next_line_bonus.c
βββ get_next_line_utils.c
βββ get_next_line_utils_bonus.cThis project doesn't include main() function, so you need to provide your own one to compile:
cc get_next_line.c get_next_line_utils.c <your_main.c>You can compile get_next_line with a custom
BUFFER_SIZEby adding the-D BUFFER_SIZE=<N>flags
Call get_next_line(fd) to get the next line of a given fd (You can use as many fd you want, in any order).
When end of file (EOF) is reached or if an error occurs, get_next_line(fd) will return NULL.
#include "get_next_line_bonus.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int fd;
char *line;
fd = open("file.txt", O_RDONLY);
if (fd == -1)
return (1);
while ((line = get_next_line(fd)))
{
printf("%s", line);
free(line);
}
close(fd);
return (0);
}π‘ Returned strings include the trailing newline (
\n) when present.
β οΈ Don't forget tofree()the line returned byget_next_line(fd)
The output line buffer grows exponentially to minimize reallocations.
This ensures O(1) amortized concatenation when appending data read from the internal buffer.
Once the line is complete, the allocated memory is reduced to the minimum required capacity before returning it.
This reduces memory footprint and avoids over-provisioning resulting from exponential growth.
To support multiple file descriptors simultaneously (required for the bonus),
each fd is associated with its own stash node stored inside a linked list.
This prevents static global arrays, avoids overflow of the .bss segment, and
keeps memory usage proportional to the number of active FDs.
Every node stores:
- its
fd - its read buffer and length
- a pointer to the next node
Nodes are created on demand and removed as soon as the fd reaches EOF or an error occurs.
No libc helpers such as memset/bzero were allowed, which would otherwise optimize buffer resets.
All operations are done manually.
Buffers are free'd as soon as possible (errors, EOF per fd, etc.).
However, since only the caller knows when an fd is no longer needed, some memory remains malloc'd until the program ends.
These are not true leaks; they remain βreachableβ and intentionally persist due to project constraints.
The algorithm centers around a per-fd stash storing:
- a fixed-size read buffer
- its current length
- its continuation pointer for the linked list of stashes
- Retrieve or create a stash for the requested
fd. - If leftover data exists in the buffer, process it first.
- Otherwise, read from the
fdinto the buffer. - Search for
\n.- If found β append the slice, adjust buffer, shrink the allocated (line) buffer and return it.
- If not β append the full buffer, reset it, read again.
- If
EOFis reached, return whatever has been accumulated (orNULL). - When an
fdfinishes, remove its stash.
This ensures:
- Minimal reads
- Perfect multi-
fdsupport - Normβcompliant modularity
- O(n) total complexity per returned line (where n is the length of the returned line)
(Each character is copied at most once thanks to exponential buffer growth.)
man 2 read(RTFM π)- Project subject
- Norm.v4
No code was generated by AI.
AI was used only to:
- reason about architectural approaches,
- clarify tester/compiler logs,
- refine explanations during debugging,
All technical decisions and implementations are original.