-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add stdin reader to Tty class (#472)
- Loading branch information
1 parent
6b5f3e3
commit d254d94
Showing
14 changed files
with
419 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,12 @@ | ||
public final class com/jakewharton/mosaic/terminal/StdinReader : java/lang/AutoCloseable { | ||
public fun close ()V | ||
public final fun interrupt ()V | ||
public final fun read ([BII)I | ||
} | ||
|
||
public final class com/jakewharton/mosaic/terminal/Tty { | ||
public static final field INSTANCE Lcom/jakewharton/mosaic/terminal/Tty; | ||
public final fun enableRawMode ()Ljava/lang/AutoCloseable; | ||
public final fun stdinReader ()Lcom/jakewharton/mosaic/terminal/StdinReader; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#include "mosaic.h" | ||
|
||
#if defined(__APPLE__) || defined(__linux__) | ||
|
||
#include "cutils.h" | ||
#include <errno.h> | ||
#include <stdlib.h> | ||
#include <sys/select.h> | ||
#include <unistd.h> | ||
|
||
typedef struct stdinReaderImpl { | ||
int pipe[2]; | ||
fd_set fds; | ||
} stdinReaderImpl; | ||
|
||
stdinReaderResult stdinReader_init() { | ||
stdinReaderResult result = {}; | ||
|
||
stdinReaderImpl *reader = calloc(1, sizeof(stdinReaderImpl)); | ||
if (unlikely(reader == NULL)) { | ||
// result.reader is set to 0 which will trigger OOM. | ||
goto ret; | ||
} | ||
|
||
if (unlikely(pipe(reader->pipe)) != 0) { | ||
result.error = errno; | ||
goto err; | ||
} | ||
|
||
result.reader = reader; | ||
|
||
ret: | ||
return result; | ||
|
||
err: | ||
free(reader); | ||
goto ret; | ||
} | ||
|
||
stdinRead stdinReader_read(stdinReader *reader, void *buffer, int count) { | ||
int pipeIn = reader->pipe[0]; | ||
|
||
FD_SET(STDIN_FILENO, &reader->fds); | ||
FD_SET(pipeIn, &reader->fds); | ||
|
||
// Our pipe's FD is always going to be higher than stdin, so use it as the max value. | ||
int nfds = pipeIn + 1; | ||
|
||
stdinRead result = {}; | ||
|
||
if (likely(select(nfds, &reader->fds, NULL, NULL, NULL) >= 0)) { | ||
if (likely(FD_ISSET(STDIN_FILENO, &reader->fds) != 0)) { | ||
int c = read(STDIN_FILENO, buffer, count); | ||
if (likely(c > 0)) { | ||
result.count = c; | ||
} else if (c == 0) { | ||
result.count = -1; // EOF | ||
} else { | ||
goto err; | ||
} | ||
} | ||
// Otherwise if the interrupt pipe was selected we return a count of 0. | ||
} else { | ||
goto err; | ||
} | ||
|
||
ret: | ||
return result; | ||
|
||
err: | ||
result.error = errno; | ||
goto ret; | ||
} | ||
|
||
platformError stdinReader_interrupt(stdinReader *reader) { | ||
int pipeOut = reader->pipe[1]; | ||
int result = write(pipeOut, " ", 1); | ||
return unlikely(result == -1) | ||
? errno | ||
: 0; | ||
} | ||
|
||
platformError stdinReader_free(stdinReader *reader) { | ||
int *pipe = reader->pipe; | ||
|
||
int result = 0; | ||
if (unlikely(close(pipe[0]) != 0)) { | ||
result = errno; | ||
} | ||
if (unlikely(close(pipe[1]) != 0 && result != 0)) { | ||
result = errno; | ||
} | ||
free(reader); | ||
return result; | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#include "mosaic.h" | ||
|
||
#if defined(WIN32) | ||
|
||
#include "cutils.h" | ||
#include <Windows.h> | ||
|
||
typedef struct stdinReaderImpl { | ||
HANDLE handles[2]; | ||
} stdinReaderImpl; | ||
|
||
stdinReaderResult stdinReader_init() { | ||
stdinReaderResult result = {}; | ||
|
||
stdinReaderImpl *reader = calloc(1, sizeof(stdinReaderImpl)); | ||
if (unlikely(reader == NULL)) { | ||
// result.reader is set to 0 which will trigger OOM. | ||
goto ret; | ||
} | ||
|
||
HANDLE stdin = GetStdHandle(STD_INPUT_HANDLE); | ||
if (unlikely(stdin == INVALID_HANDLE_VALUE)) { | ||
result.error = GetLastError(); | ||
goto err; | ||
} | ||
reader->handles[0] = stdin; | ||
|
||
HANDLE interruptEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("TODO UUID")); | ||
if (unlikely(interruptEvent == NULL)) { | ||
result.error = GetLastError(); | ||
goto err; | ||
} | ||
reader->handles[1] = interruptEvent; | ||
|
||
ret: | ||
return result; | ||
|
||
err: | ||
free(reader); | ||
goto ret; | ||
} | ||
|
||
stdinRead stdinReader_read(stdinReader *reader, void *buffer, int count) { | ||
stdinRead result = {}; | ||
DWORD waitResult = WaitForMultipleObjects(2, reader->handles, FALSE, INFINITE); | ||
if (likely(waitResult == WAIT_OBJECT_0)) { | ||
LPDWORD read = 0; | ||
if (likely(ReadConsole(reader->handles[0], buffer, count, read, NULL) != 0)) { | ||
// TODO EOF? | ||
result.count = (*read); | ||
} else { | ||
goto err; | ||
} | ||
} else if (unlikely(waitResult == WAIT_FAILED)) { | ||
goto err; | ||
} | ||
// Else if the interrupt event was selected we return a count of 0. | ||
|
||
ret: | ||
return result; | ||
|
||
err: | ||
result.error = GetLastError(); | ||
goto ret; | ||
} | ||
|
||
platformError stdinReader_interrupt(stdinReader *reader) { | ||
return likely(SetEvent(reader->handles[1]) != 0) | ||
? 0 | ||
: GetLastError(); | ||
} | ||
|
||
platformError stdinReader_free(stdinReader *reader) { | ||
DWORD result = 0; | ||
if (unlikely(CloseHandle(reader->handles[1]) != 0)) { | ||
result = GetLastError(); | ||
} | ||
free(reader); | ||
return result; | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.