From e310ca9b6bad60643dbec8dbe44244c252a9d635 Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 1 Jun 2015 11:41:28 +0200 Subject: [PATCH] windows: Implement the mp_hal_xxx functions and enable mp-readline --- windows/Makefile | 5 +- windows/mpconfigport.h | 14 ++- windows/mpconfigport.mk | 2 +- windows/msvc/sources.props | 3 +- windows/windows_mphal.c | 175 +++++++++++++++++++++++++++++++++++++ windows/windows_mphal.h | 32 +++++++ 6 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 windows/windows_mphal.c create mode 100644 windows/windows_mphal.h diff --git a/windows/Makefile b/windows/Makefile index defbf35cc152..e3a2fac4227a 100644 --- a/windows/Makefile +++ b/windows/Makefile @@ -31,10 +31,10 @@ SRC_C = \ unix/main.c \ unix/file.c \ unix/input.c \ - unix/unix_mphal.c \ unix/modos.c \ unix/modtime.c \ unix/gccollect.c \ + windows_mphal.c \ realpath.c \ init.c \ sleep.c \ @@ -43,6 +43,9 @@ OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) ifeq ($(MICROPY_USE_READLINE),1) CFLAGS_MOD += -DMICROPY_USE_READLINE=1 +SRC_C += lib/mp-readline/readline.c +else ifeq ($(MICROPY_USE_READLINE),2) +CFLAGS_MOD += -DMICROPY_USE_READLINE=2 LDFLAGS_MOD += -lreadline # the following is needed for BSD #LDFLAGS_MOD += -ltermcap diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index 70c06d3e5fcc..a9c8b7861e13 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -26,9 +26,9 @@ // options to control how Micro Python is built -// Linking with GNU readline causes binary to be licensed under GPL +// Linking with GNU readline (MICROPY_USE_READLINE == 2) causes binary to be licensed under GPL #ifndef MICROPY_USE_READLINE -#define MICROPY_USE_READLINE (0) +#define MICROPY_USE_READLINE (1) #endif #define MICROPY_ALLOC_PATH_MAX (260) //see minwindef.h for msvc or limits.h for mingw @@ -43,6 +43,7 @@ #define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1) #define MICROPY_MEM_STATS (1) #define MICROPY_DEBUG_PRINTERS (1) +#define MICROPY_USE_READLINE_HISTORY (1) #define MICROPY_HELPER_REPL (1) #define MICROPY_HELPER_LEXER_UNIX (1) #define MICROPY_ENABLE_SOURCE_LINE (1) @@ -139,6 +140,15 @@ extern const struct _mp_obj_module_t mp_module_time; { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&mp_module_time }, \ { MP_OBJ_NEW_QSTR(MP_QSTR__os), (mp_obj_t)&mp_module_os }, \ +#if MICROPY_USE_READLINE == 1 +#define MICROPY_PORT_ROOT_POINTERS \ + char *readline_hist[50]; +#endif + +#define MP_STATE_PORT MP_STATE_VM + +#define MICROPY_HAL_H "windows_mphal.h" + // We need to provide a declaration/definition of alloca() #include diff --git a/windows/mpconfigport.mk b/windows/mpconfigport.mk index f1d406d5737f..3a2c6a6b1a7f 100644 --- a/windows/mpconfigport.mk +++ b/windows/mpconfigport.mk @@ -4,7 +4,7 @@ MICROPY_FORCE_32BIT = 0 # Linking with GNU readline causes binary to be licensed under GPL -MICROPY_USE_READLINE = 0 +MICROPY_USE_READLINE = 1 # Subset of CPython time module MICROPY_PY_TIME = 1 diff --git a/windows/msvc/sources.props b/windows/msvc/sources.props index 7ec0b652bddd..f70becc78aaf 100644 --- a/windows/msvc/sources.props +++ b/windows/msvc/sources.props @@ -4,9 +4,10 @@ - + + diff --git a/windows/windows_mphal.c b/windows/windows_mphal.c new file mode 100644 index 000000000000..0fb71fa19cf8 --- /dev/null +++ b/windows/windows_mphal.c @@ -0,0 +1,175 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +#include "py/mpstate.h" + +#include MICROPY_HAL_H +#include +#include + +HANDLE std_in = NULL; +HANDLE con_out = NULL; +DWORD orig_mode; + +void mp_hal_stdio_mode_raw(void) { + if (!std_in) { + std_in = GetStdHandle(STD_INPUT_HANDLE); + } + if (!con_out) { + con_out = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0); + } + GetConsoleMode(std_in, &orig_mode); + DWORD mode = orig_mode; + mode &= ~ENABLE_ECHO_INPUT; + mode &= ~ENABLE_LINE_INPUT; + mode &= ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(std_in, mode); +} + +void mp_hal_stdio_mode_orig(void) { + assert(std_in); + SetConsoleMode(std_in, orig_mode); +} + +void mp_hal_set_interrupt_char(char c) { + assert(std_in); + if (c == CHAR_CTRL_C) { + DWORD mode; + GetConsoleMode(std_in, &mode); + mode |= ENABLE_PROCESSED_INPUT; + SetConsoleMode(std_in, mode); + } else { + DWORD mode; + GetConsoleMode(std_in, &mode); + mode &= ~ENABLE_PROCESSED_INPUT; + SetConsoleMode(std_in, mode); + } +} + +void mp_hal_move_cursor_back(uint pos) { + assert(con_out); + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(con_out, &info); + info.dwCursorPosition.X -= (short)pos; + if (info.dwCursorPosition.X < 0) { + info.dwCursorPosition.X = 0; + } + SetConsoleCursorPosition(con_out, info.dwCursorPosition); +} + +void mp_hal_erase_line_from_cursor() { + assert(con_out); + CONSOLE_SCREEN_BUFFER_INFO info; + GetConsoleScreenBufferInfo(con_out, &info); + const short len = info.dwSize.X - info.dwCursorPosition.X; + DWORD written; + FillConsoleOutputCharacter(con_out, ' ', len, info.dwCursorPosition, &written); + FillConsoleOutputAttribute(con_out, info.wAttributes, len, info.dwCursorPosition, &written); +} + +typedef struct item_t { + WORD vkey; + const char *seq; +} item_t; + +// map virtual key codes to VT100 escape sequences +STATIC item_t keyCodeMap[] = { + {VK_UP, "[A"}, + {VK_DOWN, "[B"}, + {VK_RIGHT, "[C"}, + {VK_LEFT, "[D"}, + {VK_HOME, "[H"}, + {VK_END, "[F"}, + {VK_DELETE, "[3~"}, + {0, ""} //sentinel +}; + +STATIC const char *cur_esc_seq = NULL; + +STATIC int esc_seq_process_vk(int vk) { + for (item_t *p = keyCodeMap; p->vkey != 0; ++p) { + if (p->vkey == vk) { + cur_esc_seq = p->seq; + return 27; // ESC, start of escape sequence + } + } + return 0; // nothing found +} + +STATIC int esc_seq_chr() { + if (cur_esc_seq) { + const char c = *cur_esc_seq++; + if (c) { + return c; + } + cur_esc_seq = NULL; + } + return 0; +} + +int mp_hal_stdin_rx_chr(void) { + // currently processing escape seq? + const int ret = esc_seq_chr(); + if (ret) { + return ret; + } + + // poll until key which we handle is pressed + DWORD num_read; + INPUT_RECORD rec; + for (;;) { + if (!ReadConsoleInput(std_in, &rec, 1, &num_read) || !num_read) { + return CHAR_CTRL_C; // EOF, ctrl-D + } + if (rec.EventType != KEY_EVENT || !rec.Event.KeyEvent.bKeyDown) { // only want key down events + continue; + } + const char c = rec.Event.KeyEvent.uChar.AsciiChar; + if (c) { // plain ascii char, return it + return c; + } + const int ret = esc_seq_process_vk(rec.Event.KeyEvent.wVirtualKeyCode); + if (ret) { + DEBUG_printf("vk"); + return ret; + } + } +} + +void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) { + write(1, str, len); +} + +void mp_hal_stdout_tx_strn_cooked(const char *str, mp_uint_t len) { + mp_hal_stdout_tx_strn(str, len); +} + +void mp_hal_stdout_tx_str(const char *str) { + mp_hal_stdout_tx_strn(str, strlen(str)); +} diff --git a/windows/windows_mphal.h b/windows/windows_mphal.h new file mode 100644 index 000000000000..b9ed67e71012 --- /dev/null +++ b/windows/windows_mphal.h @@ -0,0 +1,32 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "unix/unix_mphal.h" + +#define MICROPY_HAL_HAS_VT100 (0) + +void mp_hal_move_cursor_back(unsigned int pos); +void mp_hal_erase_line_from_cursor();