diff options
Diffstat (limited to 'unix')
-rw-r--r-- | unix/Makefile | 12 | ||||
-rw-r--r-- | unix/input.c | 86 | ||||
-rw-r--r-- | unix/main.c | 5 | ||||
-rw-r--r-- | unix/mpconfigport.h | 5 | ||||
-rw-r--r-- | unix/mpconfigport.mk | 5 | ||||
-rw-r--r-- | unix/unix_mphal.c | 36 | ||||
-rw-r--r-- | unix/unix_mphal.h | 3 |
7 files changed, 135 insertions, 17 deletions
diff --git a/unix/Makefile b/unix/Makefile index 0d8e35f261..790bbafbc6 100644 --- a/unix/Makefile +++ b/unix/Makefile @@ -57,7 +57,12 @@ endif endif ifeq ($(MICROPY_USE_READLINE),1) +INC += -I../lib/mp-readline CFLAGS_MOD += -DMICROPY_USE_READLINE=1 +LIB_SRC_C_EXTRA += mp-readline/readline.c +endif +ifeq ($(MICROPY_USE_READLINE),2) +CFLAGS_MOD += -DMICROPY_USE_READLINE=2 LDFLAGS_MOD += -lreadline # the following is needed for BSD #LDFLAGS_MOD += -ltermcap @@ -98,8 +103,13 @@ SRC_C = \ coverage.c \ $(SRC_MOD) +LIB_SRC_C = $(addprefix lib/,\ + $(LIB_SRC_C_EXTRA) \ + ) -OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ = $(PY_O) +OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o)) include ../py/mkrules.mk diff --git a/unix/input.c b/unix/input.c index 0a02483f70..d41487c7ef 100644 --- a/unix/input.c +++ b/unix/input.c @@ -28,26 +28,50 @@ #include <stdlib.h> #include <string.h> -#include "py/nlr.h" -#include "py/obj.h" +#include "py/mpstate.h" #include "input.h" -#if MICROPY_USE_READLINE +#if MICROPY_USE_READLINE == 1 +#include MICROPY_HAL_H +#include "lib/mp-readline/readline.h" +#elif MICROPY_USE_READLINE == 2 #include <readline/readline.h> #include <readline/history.h> #include <readline/tilde.h> -#else -#undef MICROPY_USE_READLINE_HISTORY -#define MICROPY_USE_READLINE_HISTORY (0) #endif char *prompt(char *p) { -#if MICROPY_USE_READLINE +#if MICROPY_USE_READLINE == 1 + // MicroPython supplied readline + vstr_t vstr; + vstr_init(&vstr, 16); + mp_hal_stdio_mode_raw(); + int ret = readline(&vstr, p); + mp_hal_stdio_mode_orig(); + if (ret != 0) { + vstr_clear(&vstr); + if (ret == CHAR_CTRL_D) { + // EOF + return NULL; + } else { + printf("\n"); + char *line = malloc(1); + line[0] = '\0'; + return line; + } + } + vstr_null_terminated_str(&vstr); + char *line = malloc(vstr.len + 1); + memcpy(line, vstr.buf, vstr.len + 1); + vstr_clear(&vstr); +#elif MICROPY_USE_READLINE == 2 + // GNU readline char *line = readline(p); if (line) { add_history(line); } #else + // simple read string static char buf[256]; fputs(p, stdout); char *s = fgets(buf, sizeof(buf), stdin); @@ -68,13 +92,61 @@ char *prompt(char *p) { void prompt_read_history(void) { #if MICROPY_USE_READLINE_HISTORY + #if MICROPY_USE_READLINE == 1 + readline_init0(); // will clear history pointers + char *home = getenv("HOME"); + if (home != NULL) { + vstr_t vstr; + vstr_init(&vstr, 50); + vstr_printf(&vstr, "%s/.micropython.history", home); + FILE *fp = fopen(vstr_null_terminated_str(&vstr), "r"); + if (fp != NULL) { + vstr_reset(&vstr); + for (;;) { + int c = fgetc(fp); + if (c == EOF || c == '\n') { + readline_push_history(vstr_null_terminated_str(&vstr)); + if (c == EOF) { + break; + } + vstr_reset(&vstr); + } else { + vstr_add_byte(&vstr, c); + } + } + fclose(fp); + } + vstr_clear(&vstr); + } + #elif MICROPY_USE_READLINE == 2 read_history(tilde_expand("~/.micropython.history")); + #endif #endif } void prompt_write_history(void) { #if MICROPY_USE_READLINE_HISTORY + #if MICROPY_USE_READLINE == 1 + char *home = getenv("HOME"); + if (home != NULL) { + vstr_t vstr; + vstr_init(&vstr, 50); + vstr_printf(&vstr, "%s/.micropython.history", home); + FILE *fp = fopen(vstr_null_terminated_str(&vstr), "w"); + if (fp != NULL) { + for (int i = MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)) - 1; i >= 0; i--) { + const char *line = MP_STATE_PORT(readline_hist)[i]; + if (line != NULL) { + fwrite(line, 1, strlen(line), fp); + fputc('\n', fp); + } + } + fclose(fp); + } + } + #elif MICROPY_USE_READLINE == 2 write_history(tilde_expand("~/.micropython.history")); + #endif #endif } diff --git a/unix/main.c b/unix/main.c index fb6868c88a..1cc174c269 100644 --- a/unix/main.c +++ b/unix/main.c @@ -278,8 +278,6 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) { #endif int main(int argc, char **argv) { - prompt_read_history(); - mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); pre_process_options(argc, argv); @@ -445,7 +443,9 @@ int main(int argc, char **argv) { } if (ret == NOTHING_EXECUTED) { + prompt_read_history(); ret = do_repl(); + prompt_write_history(); } #if MICROPY_PY_MICROPYTHON_MEM_INFO @@ -463,7 +463,6 @@ int main(int argc, char **argv) { #endif //printf("total bytes = %d\n", m_get_total_bytes_allocated()); - prompt_write_history(); return ret & 0xff; } diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 411817130a..2a24061c9e 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -184,10 +184,15 @@ extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj; { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \ { MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj }, +#define MP_STATE_PORT MP_STATE_VM + #define MICROPY_PORT_ROOT_POINTERS \ + const char *readline_hist[50]; \ mp_obj_t keyboard_interrupt_obj; \ void *mmap_region_head; \ +#define MICROPY_HAL_H "unix_mphal.h" + // We need to provide a declaration/definition of alloca() #ifdef __FreeBSD__ #include <stdlib.h> diff --git a/unix/mpconfigport.mk b/unix/mpconfigport.mk index 2bf86078ae..84b8e437fa 100644 --- a/unix/mpconfigport.mk +++ b/unix/mpconfigport.mk @@ -3,7 +3,10 @@ # Build 32-bit binaries on a 64-bit host MICROPY_FORCE_32BIT = 0 -# Linking with GNU readline causes binary to be licensed under GPL +# This variable can take the following values: +# 0 - no readline, just simple input +# 1 - use MicroPython version of readline +# 2 - use GNU readline (causes binary to be licensed under GPL) MICROPY_USE_READLINE = 1 # Subset of CPython time module diff --git a/unix/unix_mphal.c b/unix/unix_mphal.c index c70045b4e4..1f545f9e51 100644 --- a/unix/unix_mphal.c +++ b/unix/unix_mphal.c @@ -25,6 +25,7 @@ */ #include <unistd.h> +#include <stdlib.h> #include <string.h> #include "py/mpstate.h" @@ -35,13 +36,12 @@ STATIC void sighandler(int signum) { if (signum == SIGINT) { + if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) { + // this is the second time we are called, so die straight away + exit(1); + } mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj)); MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj); - // disable our handler so next we really die - struct sigaction sa; - sa.sa_handler = SIG_DFL; - sigemptyset(&sa.sa_mask); - sigaction(SIGINT, &sa, NULL); } } #endif @@ -67,6 +67,32 @@ void mp_hal_set_interrupt_char(char c) { } } +#if MICROPY_USE_READLINE == 1 + +#include <termios.h> + +static struct termios orig_termios; + +void mp_hal_stdio_mode_raw(void) { + // save and set terminal settings + tcgetattr(0, &orig_termios); + static struct termios termios; + termios = orig_termios; + termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + termios.c_cflag = (termios.c_cflag & ~(CSIZE | PARENB)) | CS8; + termios.c_lflag = 0; + termios.c_cc[VMIN] = 1; + termios.c_cc[VTIME] = 0; + tcsetattr(0, TCSAFLUSH, &termios); +} + +void mp_hal_stdio_mode_orig(void) { + // restore terminal settings + tcsetattr(0, TCSAFLUSH, &orig_termios); +} + +#endif + int mp_hal_stdin_rx_chr(void) { unsigned char c; int ret = read(0, &c, 1); diff --git a/unix/unix_mphal.h b/unix/unix_mphal.h index 3d9fee5c3c..209ce6d07b 100644 --- a/unix/unix_mphal.h +++ b/unix/unix_mphal.h @@ -30,6 +30,9 @@ void mp_hal_set_interrupt_char(char c); +void mp_hal_stdio_mode_raw(void); +void mp_hal_stdio_mode_orig(void); + int mp_hal_stdin_rx_chr(void); void mp_hal_stdout_tx_str(const char *str); void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len); |