From 8011e57a7259b8ae0d24e4ad53dee8ab6eec227e Mon Sep 17 00:00:00 2001 From: dd86k Date: Mon, 4 Mar 2024 15:40:39 -0500 Subject: [PATCH] Replace term_readline to term_readln --- app/shell.d | 14 +++++++------- app/term.d | 44 +++++++++++++++++++++++++++++++++++--------- dub.sdl | 7 ++++++- tests/readln.d | 21 +++++++++++++++++++++ 4 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 tests/readln.d diff --git a/app/shell.d b/app/shell.d index 1d277ef8..ff58456d 100644 --- a/app/shell.d +++ b/app/shell.d @@ -88,7 +88,7 @@ void registerHelp(void function(ref command2_help_t help)) { }*/ int shell_loop() { - // Load process if CLI specified it + // Load or attach process if CLI specified it if (globals.file) { if (adbg_debugger_spawn(&process, globals.file, AdbgSpawnOpt.argv, globals.args, 0)) @@ -123,16 +123,17 @@ int shell_loop() { term_init; LINPUT: - printf("(adbg) "); // print prompt - char* line = term_readline(null); // read line + printf("(adbg) "); + + // .ptr is temporary because a slice with a length of 0 + // also make its pointer null. + char* line = term_readln().ptr; - //TODO: remove once term gets key events if (line == null) { - printf("^D"); return 0; } - int error = shell_exec(line); // execute line + int error = shell_exec(line); if (error) printf("error: %s\n", errorstring(cast(ShellError)error)); goto LINPUT; @@ -156,7 +157,6 @@ int shell_execv(int argc, const(char) **argv) { serror("unknown command: '%s'", ucommand); return ShellError.invalidCommand; } - return command.entry(argc, argv); } diff --git a/app/term.d b/app/term.d index 1aaf8697..3b20c5b9 100644 --- a/app/term.d +++ b/app/term.d @@ -14,8 +14,8 @@ import core.stdc.stdio; extern (C): -private -int putchar(int); +private int putchar(int); +private int getchar(); version (Windows) { private import core.sys.windows.windows; @@ -358,17 +358,43 @@ L_END: } } -//TODO: Consider redoing with getchar+fwrite(stdin) +// onSpecial: tab, ^D, etc. +// make onError? +/// Read a line from stdin. +/// Params: +/// onSpecial = (Not implemented) Callback on special characters +/// Returns: Character slice; Or null on error. +char[] term_readln(void function(int) onSpecial = null) { + import core.stdc.ctype : isprint; + + // GNU readline has this set to 512 + enum BUFFERSIZE = 1024; + + __gshared char* buffer; + + if (buffer == null) { + buffer = cast(char*)malloc(BUFFERSIZE); + if (buffer == null) + return null; + } + + // NOTE: stdin is line-buffered by the host console/terminal + // Once it sees a newline, it returns, and we copy up until the newline + size_t i; +LFETCHC: + int c = getchar(); + if (c == '\n' || c == EOF) { + buffer[i] = 0; + return buffer[0..i]; + } + buffer[i++] = cast(char)c; + goto LFETCHC; +} -//TODO: term_readline_event(Key, void function(Key)) -// or just term_event_ctrld (etc.) -//TODO: damage-based display (putchar) -// instead of reprinting the whole string at every stroke -// yes, it's very noticeable on windows (because of cursor positioning?) -//TODO: Use realloc with enum INITBSZ = 2048 /// Read a line from input keystrokes /// Params: length = Pointer that will contain the number of characters in the buffer /// Returns: Internal buffer pointer +deprecated("Use term_readln") char* term_readline(int *length) { enum BUFFER_SIZE = 1024; __gshared char[BUFFER_SIZE] buffer; diff --git a/dub.sdl b/dub.sdl index 7ed4bc63..95fc196a 100644 --- a/dub.sdl +++ b/dub.sdl @@ -123,7 +123,7 @@ buildType "release-nobounds-static" { } # -# ANCHOR Unit tests +# ANCHOR Integration tests # # NOTE: These MUST be ran as "dub test -b TEST" # NOTE: Dedicated tests must only exist if one of these conditions are met @@ -145,6 +145,11 @@ buildType "readline" { sourceFiles "tests/readline.d" sourcePaths "app" "src" } +buildType "readln" { + buildOptions "unittests" + sourceFiles "tests/readln.d" + sourceFiles "app/term.d" +} # # ANCHOR Examples diff --git a/tests/readln.d b/tests/readln.d new file mode 100644 index 00000000..21a6873a --- /dev/null +++ b/tests/readln.d @@ -0,0 +1,21 @@ +module tests.readln; + +import core.stdc.stdio; +import core.stdc.ctype : isprint; +import term; + +extern (C) int putchar(int); + +unittest { + while (true) { + printf("prompt: "); + char[] input = term_readln(); + foreach (char c; input) + if (isprint(c)) + putchar(c); + else + printf("\\x%02x", c); + putchar('\n'); + printf("buffer had %d characters\n", cast(int)input.length); + } +} \ No newline at end of file