Skip to content

Commit 5c2375b

Browse files
committed
Hacky, blocking terminal I/O.
1 parent fc42c27 commit 5c2375b

File tree

1 file changed

+101
-1
lines changed

1 file changed

+101
-1
lines changed

vm/primitives.cc

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@
2020
#if defined(OS_MACOS)
2121
#include <crt_externs.h>
2222
#else
23-
extern char** environ;
23+
extern "C" char** environ;
24+
#endif
25+
26+
#if defined(OS_MACOS) || defined(OS_LINUX)
27+
#include <sys/ioctl.h>
28+
#include <termios.h>
29+
#include <unistd.h>
2430
#endif
2531

2632
#include "vm/assert.h"
@@ -274,6 +280,11 @@ const bool kFailure = false;
274280
V(355, Pipe_write) \
275281
V(356, Pipe_close) \
276282
V(357, Process_environment) \
283+
V(500, Term_start) \
284+
V(501, Term_stop) \
285+
V(502, Term_read) \
286+
V(503, Term_write) \
287+
V(504, Term_size) \
277288
V(509, print) \
278289
V(510, readFileAsBytes) \
279290
V(511, writeBytesToFile)
@@ -4007,6 +4018,95 @@ DEFINE_PRIMITIVE(Object_yourself) {
40074018
return kSuccess;
40084019
}
40094020

4021+
#if defined(OS_MACOS) || defined(OS_LINUX)
4022+
static struct termios original_term;
4023+
#endif
4024+
4025+
DEFINE_PRIMITIVE(Term_start) {
4026+
ASSERT(num_args == 0);
4027+
#if defined(OS_MACOS) || defined(OS_LINUX)
4028+
intptr_t status = tcgetattr(STDIN_FILENO, &original_term);
4029+
if (status == 0) {
4030+
struct termios term;
4031+
status = tcgetattr(STDIN_FILENO, &term);
4032+
if (status == 0) {
4033+
term.c_iflag &= ~(IXON|IXOFF|ICRNL);
4034+
term.c_oflag &= ~(OPOST);
4035+
term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
4036+
status = tcsetattr(STDIN_FILENO, TCSANOW, &term);
4037+
}
4038+
}
4039+
RETURN_SMI(status);
4040+
#else
4041+
return kFailure;
4042+
#endif
4043+
}
4044+
4045+
DEFINE_PRIMITIVE(Term_stop) {
4046+
ASSERT(num_args == 0);
4047+
#if defined(OS_MACOS) || defined(OS_LINUX)
4048+
intptr_t status = tcsetattr(STDIN_FILENO, TCSANOW, &original_term);
4049+
RETURN_SMI(status);
4050+
#else
4051+
return kFailure;
4052+
#endif
4053+
}
4054+
4055+
DEFINE_PRIMITIVE(Term_size) {
4056+
ASSERT(num_args == 0);
4057+
#if defined(OS_MACOS) || defined(OS_LINUX)
4058+
struct winsize w;
4059+
w.ws_col = 0;
4060+
w.ws_row = 0;
4061+
intptr_t status = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
4062+
if (status != 0) {
4063+
RETURN_SMI(status);
4064+
}
4065+
Array result = H->AllocateArray(2);
4066+
result.set_element(0, SmallInteger::New(w.ws_row));
4067+
result.set_element(1, SmallInteger::New(w.ws_col));
4068+
RETURN(result);
4069+
#else
4070+
return kFailure;
4071+
#endif
4072+
}
4073+
4074+
DEFINE_PRIMITIVE(Term_write) {
4075+
ASSERT(num_args == 1);
4076+
#if defined(OS_MACOS) || defined(OS_LINUX)
4077+
Bytes buffer = static_cast<Bytes>(I->Stack(0));
4078+
if (!buffer->IsBytes()) return kFailure;
4079+
4080+
size_t length = buffer->Size();
4081+
size_t start = 0;
4082+
while (start != length) {
4083+
size_t written = write(STDOUT_FILENO,
4084+
buffer->element_addr(start),
4085+
length - start);
4086+
if (written == 0) {
4087+
FATAL("Failed to write");
4088+
}
4089+
start += written;
4090+
}
4091+
RETURN_SELF();
4092+
#else
4093+
return kFailure;
4094+
#endif
4095+
}
4096+
4097+
DEFINE_PRIMITIVE(Term_read) {
4098+
ASSERT(num_args == 0);
4099+
#if defined(OS_MACOS) || defined(OS_LINUX)
4100+
uint8_t byte;
4101+
if (read(STDIN_FILENO, &byte, 1) <= 0) {
4102+
FATAL("Failed to read");
4103+
}
4104+
RETURN_SMI(static_cast<intptr_t>(byte));
4105+
#else
4106+
return kFailure;
4107+
#endif
4108+
}
4109+
40104110
PrimitiveFunction* Primitives::primitive_table_[kNumPrimitives] = {};
40114111

40124112
void Primitives::Startup() {

0 commit comments

Comments
 (0)