summaryrefslogtreecommitdiffstatshomepage
path: root/unix
diff options
context:
space:
mode:
Diffstat (limited to 'unix')
-rw-r--r--unix/Makefile12
-rw-r--r--unix/input.c86
-rw-r--r--unix/main.c5
-rw-r--r--unix/mpconfigport.h5
-rw-r--r--unix/mpconfigport.mk5
-rw-r--r--unix/unix_mphal.c36
-rw-r--r--unix/unix_mphal.h3
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);