--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* get_next_line.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2025/11/01 10:55:35 by agilliar #+# #+# */
+/* Updated: 2025/11/06 18:00:50 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "get_next_line.h"
+
+void buffer_pushchar(t_buf *buf, char c);
+void buffers_remove(t_readbufs *bufs, int fd);
+void *ft_memcpy(void *dest, const void *src, size_t n);
+bool readbuf_read(t_readbuf *buf);
+t_readbuf *buffers_get(t_readbufs *bufs, int fd);
+
+char *buffer_finish(t_buf buf, t_readbufs *buffers, int fd)
+{
+ if (buf.buf)
+ buffer_pushchar(&buf, '\0');
+ if (!buf.buf)
+ buffers_remove(buffers, fd);
+ return (buf.buf);
+}
+
+/*
+ returns whether it should keep going
+*/
+bool buffer_empty(t_readbuf *buf, t_buf *dst)
+{
+ size_t i;
+
+ if (buf->written == 0)
+ return (false);
+ i = 0;
+ while (i < buf->written)
+ {
+ buffer_pushchar(dst, buf->buf[i++]);
+ if (dst->buf == NULL)
+ return (false);
+ if (dst->buf[dst->len - 1] == '\n')
+ break ;
+ }
+ buf->written -= i;
+ ft_memcpy(buf->buf, &buf->buf[i], buf->written);
+ if (dst->buf[dst->len - 1] == '\n')
+ return (false);
+ return (true);
+}
+
+char *get_next_line(int fd)
+{
+ static t_readbufs buffers = {
+ .used = 0
+ };
+ t_readbuf *buf;
+ t_buf res;
+
+ res.len = 0;
+ res.capacity = 0;
+ res.buf = NULL;
+ buf = buffers_get(&buffers, fd);
+ if (!buf)
+ return (NULL);
+ while (true)
+ {
+ if (!readbuf_read(buf))
+ {
+ buffers_remove(&buffers, fd);
+ free(res.buf);
+ return (NULL);
+ }
+ if (!buffer_empty(buf, &res))
+ return (buffer_finish(res, &buffers, fd));
+ }
+}
+
+/*
+#include <fcntl.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ char *nl;
+ bool any_line;
+
+ for (int i = 1; i < argc; i++)
+ ((int *)argv)[i] = open(argv[i], O_RDONLY);
+ any_line = true;
+ for (int i = 0; any_line; i++)
+ {
+ any_line = false;
+ for (int j = 1; j < argc; j++)
+ {
+ nl = get_next_line(((int *)argv)[j]);
+ if (!nl)
+ continue;
+ any_line = true;
+ printf("line %i file %i: %s", i, j, nl);
+ free(nl);
+ }
+ }
+ for (char *nl; (nl = get_next_line(0));)
+ {
+ printf("stdin: %s", nl);
+ free(nl);
+ }
+}
+*/
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* get_next_line.h :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2025/11/01 10:38:19 by agilliar #+# #+# */
+/* Updated: 2025/11/06 17:20:44 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#ifndef GET_NEXT_LINE_H
+# define GET_NEXT_LINE_H
+
+# include <stddef.h>
+
+# ifndef BUFFER_SIZE
+# define BUFFER_SIZE 256
+# endif
+
+# ifndef GNL_MAX_FD
+# define GNL_MAX_FD 256
+# endif
+
+typedef struct s_buf
+{
+ size_t len;
+ size_t capacity;
+ char *buf;
+} t_buf;
+
+typedef struct s_readbuf
+{
+ size_t written;
+ int fd;
+ char buf[BUFFER_SIZE];
+} t_readbuf;
+
+typedef struct s_readbufs
+{
+ size_t used;
+ t_readbuf bufs[GNL_MAX_FD];
+} t_readbufs;
+
+char *get_next_line(int fd);
+
+#endif
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* get_next_line_utils.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <marvin@42.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2025/11/06 17:56:20 by agilliar #+# #+# */
+/* Updated: 2025/11/06 17:58:50 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "get_next_line.h"
+
+t_readbuf *buffers_get(t_readbufs *bufs, int fd)
+{
+ size_t i;
+
+ i = 0;
+ while (i < bufs->used && bufs->bufs[i].fd != fd)
+ i++;
+ if (i == GNL_MAX_FD)
+ return (NULL);
+ if (i == bufs->used)
+ {
+ bufs->bufs[i].written = 0;
+ bufs->bufs[i].fd = fd;
+ bufs->used++;
+ }
+ return (&bufs->bufs[i]);
+}
+
+void buffers_remove(t_readbufs *bufs, int fd)
+{
+ size_t i;
+
+ i = 0;
+ while (i < bufs->used && bufs->bufs[i].fd != fd)
+ i++;
+ if (i == GNL_MAX_FD)
+ return ;
+ bufs->bufs[i] = bufs->bufs[--bufs->used];
+}
+
+bool readbuf_read(t_readbuf *buf)
+{
+ int n;
+
+ if (buf->written != 0)
+ return (true);
+ n = read(buf->fd, &buf->buf, BUFFER_SIZE);
+ if (n < 0)
+ return (false);
+ buf->written = n;
+ return (true);
+}
+
+void *ft_memcpy(void *dest, const void *src, size_t n)
+{
+ size_t i;
+
+ i = 0;
+ while (i < n)
+ {
+ ((unsigned char *)dest)[i] = ((unsigned char *)src)[i];
+ i++;
+ }
+ return (dest);
+}
+
+/*
+ frees its own resources on failure
+*/
+void buffer_pushchar(t_buf *buf, char c)
+{
+ size_t new_capacity;
+ char *new_buf;
+
+ if (buf->len + 1 > buf->capacity)
+ {
+ new_capacity = buf->len + 1;
+ if (new_capacity < BUFFER_SIZE + buf->capacity * 2)
+ new_capacity = BUFFER_SIZE + buf->capacity * 2;
+ new_buf = malloc(new_capacity);
+ if (!new_buf)
+ {
+ free(buf->buf);
+ buf->buf = NULL;
+ return ;
+ }
+ ft_memcpy(new_buf, buf->buf, buf->len);
+ free(buf->buf);
+ buf->buf = new_buf;
+ buf->capacity = new_capacity;
+ }
+ buf->buf[buf->len++] = c;
+}