Skip to content

ports/unix: Add full uos.dupterm support. #6080

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions extmod/vfs_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,17 @@ extern const mp_obj_type_t mp_type_vfs_posix_textio;

mp_obj_t mp_vfs_posix_file_open(const mp_obj_type_t *type, mp_obj_t file_in, mp_obj_t mode_in);

#if MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE
typedef struct _mp_obj_vfs_posix_file_t {
mp_obj_base_t base;
int fd;
bool raw_stdio;
} mp_obj_vfs_posix_file_t;

extern const mp_obj_vfs_posix_file_t mp_sys_stdin_obj;
extern const mp_obj_vfs_posix_file_t mp_sys_stdout_obj;
extern const mp_obj_vfs_posix_file_t mp_sys_stderr_obj;
extern const mp_obj_vfs_posix_file_t mp_sys_raw_stdio_obj;
#endif

#endif // MICROPY_INCLUDED_EXTMOD_VFS_POSIX_H
33 changes: 20 additions & 13 deletions extmod/vfs_posix_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@
#define fsync _commit
#endif

typedef struct _mp_obj_vfs_posix_file_t {
mp_obj_base_t base;
int fd;
} mp_obj_vfs_posix_file_t;

#ifdef MICROPY_CPYTHON_COMPAT
STATIC void check_fd_is_open(const mp_obj_vfs_posix_file_t *o) {
if (o->fd < 0) {
Expand Down Expand Up @@ -137,7 +132,13 @@ STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, i
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o);
ssize_t r;
MP_HAL_RETRY_SYSCALL(r, read(o->fd, buf, size), {
int fd = o->fd;
#if MICROPY_PY_OS_DUPTERM
if (fd <= STDERR_FILENO && o->raw_stdio) {
fd = STDIN_FILENO;
}
#endif
MP_HAL_RETRY_SYSCALL(r, read(fd, buf, size), {
*errcode = err;
return MP_STREAM_ERROR;
});
Expand All @@ -147,14 +148,19 @@ STATIC mp_uint_t vfs_posix_file_read(mp_obj_t o_in, void *buf, mp_uint_t size, i
STATIC mp_uint_t vfs_posix_file_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
mp_obj_vfs_posix_file_t *o = MP_OBJ_TO_PTR(o_in);
check_fd_is_open(o);
int fd = o->fd;
#if MICROPY_PY_OS_DUPTERM
if (o->fd <= STDERR_FILENO) {
mp_hal_stdout_tx_strn(buf, size);
return size;
if (fd <= STDERR_FILENO) {
if (o->raw_stdio) {
fd = STDOUT_FILENO;
} else {
mp_hal_stdout_tx_strn(buf, size);
return size;
}
}
#endif
ssize_t r;
MP_HAL_RETRY_SYSCALL(r, write(o->fd, buf, size), {
MP_HAL_RETRY_SYSCALL(r, write(fd, buf, size), {
*errcode = err;
return MP_STREAM_ERROR;
});
Expand Down Expand Up @@ -262,8 +268,9 @@ const mp_obj_type_t mp_type_vfs_posix_textio = {
.locals_dict = (mp_obj_dict_t *)&vfs_posix_rawfile_locals_dict,
};

const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, STDIN_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, STDOUT_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, STDERR_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stdin_obj = {{&mp_type_textio}, .fd=STDIN_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stdout_obj = {{&mp_type_textio}, .fd=STDOUT_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_stderr_obj = {{&mp_type_textio}, .fd=STDERR_FILENO};
const mp_obj_vfs_posix_file_t mp_sys_raw_stdio_obj = {{&mp_type_textio}, .fd=STDIN_FILENO, .raw_stdio=true};

#endif // MICROPY_VFS_POSIX || MICROPY_VFS_POSIX_FILE
9 changes: 8 additions & 1 deletion ports/unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);

STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
(void)env;
#if MICROPY_PY_OS_DUPTERM
mp_uos_dupterm_tx_strn(str, len);
#else
ssize_t ret;
MP_HAL_RETRY_SYSCALL(ret, write(STDERR_FILENO, str, len), {});
mp_uos_dupterm_tx_strn(str, len);
#endif
}

const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
Expand Down Expand Up @@ -537,6 +540,10 @@ MP_NOINLINE int main_(int argc, char **argv) {
}
#endif

#if MICROPY_PY_OS_DUPTERM
init_dupterm_stdio();
#endif

// Here is some example code to create a class and instance of that class.
// First is the Python, then the C code.
//
Expand Down
4 changes: 4 additions & 0 deletions ports/unix/mphalport.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,7 @@ enum {

void mp_hal_get_mac(int idx, uint8_t buf[6]);
#endif

#if MICROPY_PY_OS_DUPTERM
void init_dupterm_stdio();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have mp_ prefix since it is in a header file. Or even better, mp_unix_ since it is specific to the unix port.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was loath to change the name of an existing file, but I too thought it was oddly inconsistent in name.

#endif
77 changes: 28 additions & 49 deletions ports/unix/unix_mphal.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@
#include "py/mphal.h"
#include "py/mpthread.h"
#include "py/runtime.h"
#include "py/stream.h"
#include "py/mperrno.h"
#include "extmod/misc.h"
#include "extmod/vfs_posix.h"

#ifndef _WIN32
#include <signal.h>
Expand Down Expand Up @@ -64,8 +67,12 @@ STATIC void sighandler(int signum) {
}
#endif

// Implementation for lib/utils/interupt_char.h
int mp_interrupt_char = -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be nice to have a comment that explains this is the mp_interrupt_char from lib/utils/interupt_char.h

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Yes I had to add this just to allow compilation with MICROPY_PY_OS_DUPTERM enabled.


void mp_hal_set_interrupt_char(char c) {
// configure terminal settings to (not) let ctrl-C through
mp_interrupt_char = c;
if (c == CHAR_CTRL_C) {
#ifndef _WIN32
// enable signal handler
Expand Down Expand Up @@ -114,72 +121,44 @@ void mp_hal_stdio_mode_orig(void) {
#endif

#if MICROPY_PY_OS_DUPTERM
static int call_dupterm_read(size_t idx) {
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t read_m[3];
mp_load_method(MP_STATE_VM(dupterm_objs[idx]), MP_QSTR_read, read_m);
read_m[2] = MP_OBJ_NEW_SMALL_INT(1);
mp_obj_t res = mp_call_method_n_kw(1, 0, read_m);
if (res == mp_const_none) {
return -2;
}
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(res, &bufinfo, MP_BUFFER_READ);
if (bufinfo.len == 0) {
mp_printf(&mp_plat_print, "dupterm: EOF received, deactivating\n");
MP_STATE_VM(dupterm_objs[idx]) = MP_OBJ_NULL;
return -1;
}
nlr_pop();
return *(byte *)bufinfo.buf;
} else {
// Temporarily disable dupterm to avoid infinite recursion
mp_obj_t save_term = MP_STATE_VM(dupterm_objs[idx]);
MP_STATE_VM(dupterm_objs[idx]) = NULL;
mp_printf(&mp_plat_print, "dupterm: ");
mp_obj_print_exception(&mp_plat_print, nlr.ret_val);
MP_STATE_VM(dupterm_objs[idx]) = save_term;
}

return -1;
void init_dupterm_stdio() {
MP_STATE_VM(dupterm_objs[0]) = MP_OBJ_FROM_PTR(&mp_sys_raw_stdio_obj);
}
#endif

int mp_hal_stdin_rx_chr(void) {
#if MICROPY_PY_OS_DUPTERM
// TODO only support dupterm one slot at the moment
if (MP_STATE_VM(dupterm_objs[0]) != MP_OBJ_NULL) {
int c;
do {
c = call_dupterm_read(0);
} while (c == -2);
if (c == -1) {
goto main_term;
}
if (c == '\n') {
c = '\r';
}
return c;
int c;
do {
c = mp_uos_dupterm_rx_chr();
} while (c == -2);
if (c == '\n') {
c = '\r';
}
main_term:;
#endif

return c;

#else // ! MICROPY_PY_OS_DUPTERM
unsigned char c;
ssize_t ret;
MP_HAL_RETRY_SYSCALL(ret, read(STDIN_FILENO, &c, 1), {});
int errcode = 0;
const mp_stream_p_t *stream_p = mp_get_stream(&mp_sys_raw_stdio_obj);
mp_uint_t ret = stream_p->read((mp_obj_t)&mp_sys_raw_stdio_obj, &c, 1, &errcode);
if (ret == 0) {
c = 4; // EOF, ctrl-D
} else if (c == '\n') {
c = '\r';
}
return c;
#endif
}

void mp_hal_stdout_tx_strn(const char *str, size_t len) {
ssize_t ret;
MP_HAL_RETRY_SYSCALL(ret, write(STDOUT_FILENO, str, len), {});
#if MICROPY_PY_OS_DUPTERM
mp_uos_dupterm_tx_strn(str, len);
#else
int errcode = 0;
const mp_stream_p_t *stream_p = mp_get_stream(&mp_sys_raw_stdio_obj);
stream_p->write((mp_obj_t)&mp_sys_raw_stdio_obj, str, len, &errcode);
#endif
}

// cooked is same as uncooked because the terminal does some postprocessing
Expand Down