From 14f9a6eb787d869f16a67916fcaef25d1e248cdb Mon Sep 17 00:00:00 2001 From: Axy Date: Sat, 1 Nov 2025 16:36:51 +0100 Subject: [PATCH 1/1] Full impl --- .editorconfig | 2 + .gitignore | 3 + get_next_line.c | 222 ++++++++++++++++++++++++++++++++++++++++++++++++ get_next_line.h | 20 +++++ 4 files changed, 247 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 get_next_line.c create mode 100644 get_next_line.h diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0b225af --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[*] +indent_style = tab diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a22a1c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.a +*.out diff --git a/get_next_line.c b/get_next_line.c new file mode 100644 index 0000000..90f6879 --- /dev/null +++ b/get_next_line.c @@ -0,0 +1,222 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* get_next_line.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/11/01 10:55:35 by agilliar #+# #+# */ +/* Updated: 2025/11/01 16:36:45 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include + +typedef struct s_buf +{ + size_t len; + size_t capacity; + size_t search_offset; + char *buf; +} t_buf; + +typedef struct s_list +{ + int fd; + t_buf buf; + struct s_list *next; +} t_list; + +#define BUFFER_SIZE 256 + +/* + not restrict, therefor it is safe to use it on overlapping memory regions so + long as the destination is before the source +*/ +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); +} + +/* + returns false when an allocation error occured +*/ +bool buffer_reserve(t_buf *buf, size_t extra) +{ + size_t new_capacity; + char *new_buf; + + if (buf->len + extra <= buf->capacity) + return (true); + new_capacity = buf->len + extra; + if (new_capacity < buf->capacity * 2) + new_capacity = buf->capacity * 2; + new_buf = malloc(new_capacity); + if (!new_buf) + return (false); + ft_memcpy(new_buf, buf->buf, buf->len); + free(buf->buf); + buf->buf = new_buf; + buf->capacity = new_capacity; + return (true); +} + +bool buffer_read(t_buf *buf, int fd) +{ + char read_buf[BUFFER_SIZE]; + ssize_t res; + + res = read(fd, read_buf, BUFFER_SIZE); + if (res < 1 || !buffer_reserve(buf, res)) + return (false); + ft_memcpy(&buf->buf[buf->len], read_buf, res); + buf->len += res; + return (true); +} + +/* + returns false when an allocation error occured +*/ +bool buffer_shrink_near_fit(t_buf *buf) +{ + char *new_buf; + + if (buf->capacity <= buf->len * 2 + BUFFER_SIZE) + return (true); + new_buf = malloc(buf->len * 2); + if (!new_buf) + return (false); + ft_memcpy(new_buf, buf->buf, buf->len); + free(buf->buf); + buf->buf = new_buf; + buf->capacity = buf->len * 2; + return (true); +} + +bool buffer_search(t_buf *buf) +{ + while (buf->search_offset < buf->len) + if (buf->buf[buf->search_offset++] == '\n') + return (true); + return (false); +} + +t_buf *buffers_get(t_list **buffers, int fd) +{ + while (*buffers && (*buffers)->fd != fd) + buffers = &(*buffers)->next; + if (*buffers) + return (&(*buffers)->buf); + (*buffers) = malloc(sizeof(t_list)); + if (!*buffers) + return (NULL); + (*buffers)->next = NULL; + (*buffers)->fd = fd; + (*buffers)->buf.len = 0; + (*buffers)->buf.capacity = 0; + (*buffers)->buf.search_offset = 0; + (*buffers)->buf.buf = malloc(0); + return (&(*buffers)->buf); +} + +void *buffers_del(t_list **buffers, int fd) +{ + t_list *next; + + while (*buffers && (*buffers)->fd != fd) + buffers = &(*buffers)->next; + if (!*buffers) + return (NULL); + free((*buffers)->buf.buf); + next = (*buffers)->next; + free(*buffers); + *buffers = next; + return (NULL); +} + +char *ft_substr(const char *src, size_t len) +{ + char *res; + + res = malloc(len + 1); + if (!res) + return (res); + ft_memcpy(res, src, len); + res[len] = '\0'; + return (res); +} + +char *buffer_gnl(t_buf *buf, t_list **buffers, int fd) +{ + char *res; + + res = ft_substr(buf->buf, buf->search_offset); + if (!res) + return (buffers_del(buffers, fd)); + buf->len -= buf->search_offset; + ft_memcpy(buf->buf, &buf->buf[buf->search_offset], buf->len); + buf->search_offset = 0; + buffer_shrink_near_fit(buf); + return (res); +} + +char *get_next_line(int fd) +{ + static t_list *buffers = NULL; + t_buf *buf; + char *res; + + buf = buffers_get(&buffers, fd); + if (!buf) + return (NULL); + while (buf->len != buf->search_offset || buffer_read(buf, fd)) + { + if (buf->search_offset == buf->len) + { + res = ft_substr(buf->buf, buf->len); + buffers_del(&buffers, fd); + return (res); + } + if (buffer_search(buf)) + return (buffer_gnl(buf, &buffers, fd)); + } + return (buffers_del(&buffers, fd)); +} + +/* +#include +#include + +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); + } + } +} +*/ diff --git a/get_next_line.h b/get_next_line.h new file mode 100644 index 0000000..5b88a19 --- /dev/null +++ b/get_next_line.h @@ -0,0 +1,20 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* get_next_line.h :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: agilliar +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/11/01 10:38:19 by agilliar #+# #+# */ +/* Updated: 2025/11/01 13:17:10 by agilliar ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#ifndef GET_NEXT_LINE_H +# define GET_NEXT_LINE_H + +# include + +char *get_next_line(int fd); + +#endif -- 2.51.0