From c7a6bdec4984ca90037aeecad5abf3726d7fb48e Mon Sep 17 00:00:00 2001 From: Derick Alangi Date: Wed, 16 Jun 2021 12:14:23 +0100 Subject: [PATCH] Improve REPL to use a byte buffer with `fgetc()` to read line Introduced a new function `readLine()` that utilizes the byte buffer together with `fgetc()` to read input from the STDIN. This enables the REPL to read characters one at a time for validation & in a safer manner where the buffer gets to be resized if it's full. --- cli/repl.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/cli/repl.c b/cli/repl.c index aab99b0..25766ab 100644 --- a/cli/repl.c +++ b/cli/repl.c @@ -12,6 +12,7 @@ #include "utils.h" // FIXME: use fgetc char by char till reach a new line. +// TODO: Will need refactoring to use a byte buffer. // // Read a line from stdin and returns it without the line ending. Accepting // an optional argument [length] (could be NULL). Note that the returned string @@ -29,6 +30,19 @@ const char* read_line(uint32_t* length) { return mem; } +// Reads a line one character at a time and stop reading when we hit the +// EOF or a new line. The buffer resizes itself when count == capacity. +static void readLine(ByteBuffer* buff) { + do { + char c = fgetc(stdin); + if (c == EOF || c == '\n') break; + + byteBufferWrite(buff, (uint8_t)c); + } while (true); + + byteBufferWrite(buff, '\0'); +} + // Returns true if the string is empty, used to check if the input line is // empty to skip compilation of empty string. static inline bool is_str_empty(const char* line) { @@ -57,6 +71,10 @@ int repl(PKVM* vm, const PkCompileOptions* options) { ByteBuffer lines; byteBufferInit(&lines); + // A buffer to store a line read from stdin. + ByteBuffer line; + byteBufferInit(&line); + // Will be set to true if the compilation failed with unexpected EOF to add // more lines to the [lines] buffer. bool need_more_lines = false; @@ -72,20 +90,19 @@ int repl(PKVM* vm, const PkCompileOptions* options) { } // Read a line from stdin and add the line to the lines buffer. - uint32_t length = 0; - const char* line = read_line(&length); - bool is_empty = is_str_empty(line); + readLine(&line); + bool is_empty = is_str_empty((const char*)line.data); // If the line is empty, we don't have to compile it. if (is_empty && !need_more_lines) { - free((void*)line); + byteBufferClear(&line); ASSERT(lines.count == 0, OOPS); continue; } if (lines.count != 0) byteBufferWrite(&lines, '\n'); - byteBufferAddString(&lines, line, length); - free((void*)line); + byteBufferAddString(&lines, (const char*)line.data, line.count - 1); + byteBufferClear(&line); byteBufferWrite(&lines, '\0'); // Compile the buffer to the module.