From 47d505dcbb123890a7f7fef00cb104b721682765 Mon Sep 17 00:00:00 2001 From: apio Date: Sat, 20 May 2023 15:36:30 +0200 Subject: [PATCH] libc: Add getline() and getdelim() --- apps/su.cpp | 2 +- libc/include/stdio.h | 8 ++++++ libc/src/stdio.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++ libc/src/strftime.cpp | 2 +- libc/src/unistd.cpp | 7 ++--- 5 files changed, 74 insertions(+), 5 deletions(-) diff --git a/apps/su.cpp b/apps/su.cpp index 2109a663..ef7d3514 100644 --- a/apps/su.cpp +++ b/apps/su.cpp @@ -33,7 +33,7 @@ char* getpass() return nullptr; } - static char buf[1024]; + static char buf[BUFSIZ]; char* rc = fgets(buf, sizeof(buf), stdin); restore_terminal(); diff --git a/libc/include/stdio.h b/libc/include/stdio.h index eb6abb83..aef67d83 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -26,6 +26,8 @@ extern FILE* stderr; #define stdout stdout #define stderr stderr +#define BUFSIZ 1024 + #ifdef __cplusplus extern "C" { @@ -96,6 +98,12 @@ extern "C" /* Read a line from stream. */ char* fgets(char* buf, size_t size, FILE* stream); + /* Read a line from stream and store it in a dynamically-allocated buffer. */ + ssize_t getline(char** linep, size_t* n, FILE* stream); + + /* Read a line from stream and store it in a dynamically-allocated buffer. */ + ssize_t getdelim(char** linep, size_t* n, int delim, FILE* stream); + /* Clear the error and end-of-file indicators in stream. */ void clearerr(FILE* stream); diff --git a/libc/src/stdio.cpp b/libc/src/stdio.cpp index 648d6c23..cef9bd27 100644 --- a/libc/src/stdio.cpp +++ b/libc/src/stdio.cpp @@ -236,6 +236,66 @@ extern "C" return buf; } + ssize_t getline(char** linep, size_t* n, FILE* stream) + { + return getdelim(linep, n, '\n', stream); + } + + ssize_t getdelim(char** linep, size_t* n, int delim, FILE* stream) + { + if (!n || !linep) + { + errno = EINVAL; + return -1; + } + + char* buf = *linep; + size_t size = *n; + size_t len = 0; + + if (!buf) + { + buf = (char*)malloc(BUFSIZ); + size = BUFSIZ; + if (!buf) return -1; + *linep = buf; + *n = size; + } + + while (1) + { + int c = fgetc(stream); + if (c == EOF) break; + + if (len == size) + { + buf = (char*)realloc(buf, size + 64); + size += 64; + if (!buf) return -1; + *linep = buf; + *n = size; + } + + buf[len++] = (char)c; + if (c == delim) break; + } + + if (len == 0) return -1; + + if (len == size) + { + buf = (char*)realloc(buf, size + 16); + size += 16; + if (!buf) return -1; + *linep = buf; + *n = size; + } + + buf[len] = '\0'; + + return (ssize_t)len; + } + void clearerr(FILE* stream) { stream->_eof = stream->_err = 0; diff --git a/libc/src/strftime.cpp b/libc/src/strftime.cpp index 4db7b4c7..92bbbae3 100644 --- a/libc/src/strftime.cpp +++ b/libc/src/strftime.cpp @@ -36,7 +36,7 @@ static bool try_format(strftime_state& state, const char* format, ...) va_list ap; va_start(ap, format); - char buf[1024]; + char buf[BUFSIZ]; vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); diff --git a/libc/src/unistd.cpp b/libc/src/unistd.cpp index 42c7296e..bfe870a3 100644 --- a/libc/src/unistd.cpp +++ b/libc/src/unistd.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -347,17 +348,17 @@ extern "C" } else { - buf = (char*)malloc(1024); + buf = (char*)malloc(BUFSIZ); if (!buf) return nullptr; - ssize_t rc = __getcwd_wrapper(buf, 1024); + ssize_t rc = __getcwd_wrapper(buf, BUFSIZ); if (rc < 0) { free(buf); return nullptr; } - if (rc > 1024) + if (rc > BUFSIZ) { free(buf);