Skip to content
Closed
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
28 changes: 17 additions & 11 deletions lib/mp-readline/readline.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,17 +112,7 @@ int readline_process_char(int c) {
} else if (c == '\r') {
// newline
mp_hal_stdout_tx_str("\r\n");
if (rl.line->len > rl.orig_line_len && (MP_STATE_PORT(readline_hist)[0] == NULL || strcmp(MP_STATE_PORT(readline_hist)[0], rl.line->buf + rl.orig_line_len) != 0)) {
// a line which is not empty and different from the last one
// so update the history
char *most_recent_hist = str_dup_maybe(vstr_null_terminated_str(rl.line) + rl.orig_line_len);
if (most_recent_hist != NULL) {
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1];
}
MP_STATE_PORT(readline_hist)[0] = most_recent_hist;
}
}
readline_push_history(vstr_null_terminated_str(rl.line) + rl.orig_line_len);
return 0;
} else if (c == 27) {
// escape sequence
Expand Down Expand Up @@ -312,3 +302,19 @@ int readline(vstr_t *line, const char *prompt) {
}
}
}

void readline_push_history(const char *line) {
if (line[0] != '\0'
&& (MP_STATE_PORT(readline_hist)[0] == NULL
|| strcmp(MP_STATE_PORT(readline_hist)[0], line) != 0)) {
// a line which is not empty and different from the last one
// so update the history
char *most_recent_hist = str_dup_maybe(line);
if (most_recent_hist != NULL) {
for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
MP_STATE_PORT(readline_hist)[i] = MP_STATE_PORT(readline_hist)[i - 1];
}
MP_STATE_PORT(readline_hist)[0] = most_recent_hist;
}
}
}
1 change: 1 addition & 0 deletions lib/mp-readline/readline.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

void readline_init0(void);
int readline(vstr_t *line, const char *prompt);
void readline_push_history(const char *line);

void readline_init(vstr_t *line, const char *prompt);
void readline_note_newline(const char *prompt);
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/repl_basic.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# basic REPL tests
print(1)
OA

16 changes: 9 additions & 7 deletions unix/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ include ../py/py.mk

INC = -I.
INC += -I..
INC += -I../lib/mp-readline
INC += -I$(BUILD)

# compiler settings
Expand Down Expand Up @@ -56,12 +57,6 @@ endif
endif
endif

ifeq ($(MICROPY_USE_READLINE),1)
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
LDFLAGS_MOD += -lreadline
# the following is needed for BSD
#LDFLAGS_MOD += -ltermcap
endif
ifeq ($(MICROPY_PY_TIME),1)
CFLAGS_MOD += -DMICROPY_PY_TIME=1
SRC_MOD += modtime.c
Expand Down Expand Up @@ -95,10 +90,17 @@ SRC_C = \
modos.c \
alloc.c \
coverage.c \
unix_mphal.c \
$(SRC_MOD)

LIB_SRC_C = $(addprefix lib/,\
mp-readline/readline.c \
)


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

Expand Down
91 changes: 58 additions & 33 deletions unix/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,53 +28,78 @@
#include <stdlib.h>
#include <string.h>

#include "py/nlr.h"
#include "py/obj.h"
#include "py/mpstate.h"
#include "lib/mp-readline/readline.h"
#include "input.h"

#if MICROPY_USE_READLINE
#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
char *line = readline(p);
if (line) {
add_history(line);
}
#else
static char buf[256];
fputs(p, stdout);
char *s = fgets(buf, sizeof(buf), stdin);
if (!s) {
return NULL;
}
int l = strlen(buf);
if (buf[l - 1] == '\n') {
buf[l - 1] = 0;
} else {
l++;
vstr_t vstr;
vstr_init(&vstr, 16);
int ret = readline(&vstr, p);
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;
}
}
char *line = malloc(l);
memcpy(line, buf, l);
#endif
vstr_null_terminated_str(&vstr);
char *line = malloc(vstr.len + 1);
memcpy(line, vstr.buf, vstr.len + 1);
vstr_clear(&vstr);
return line;
}

void prompt_read_history(void) {
#if MICROPY_USE_READLINE_HISTORY
read_history(tilde_expand("~/.micropython.history"));
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");
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);
}
}
vstr_clear(&vstr);
fclose(fp);
}
#endif
}

void prompt_write_history(void) {
#if MICROPY_USE_READLINE_HISTORY
write_history(tilde_expand("~/.micropython.history"));
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");
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);
}
#endif
}

Expand Down
49 changes: 12 additions & 37 deletions unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "py/gc.h"
#include "py/stackctrl.h"
#include "genhdr/mpversion.h"
#include "unix_mphal.h"
#include "input.h"

// Command line options, with their defaults
Expand All @@ -57,22 +58,6 @@ mp_uint_t mp_verbose_flag = 0;
long heap_size = 128*1024 * (sizeof(mp_uint_t) / 4);
#endif

#ifndef _WIN32
#include <signal.h>

STATIC void sighandler(int signum) {
if (signum == SIGINT) {
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

STATIC void stderr_print_strn(void *env, const char *str, mp_uint_t len) {
(void)env;
fwrite(str, len, 1, stderr);
Expand Down Expand Up @@ -110,14 +95,7 @@ STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind,
return 1;
}

#ifndef _WIN32
// enable signal handler
struct sigaction sa;
sa.sa_handler = sighandler;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = SIG_DFL;
#endif
mp_hal_set_interrupt_char(3); // ctrl-C

nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
Expand All @@ -144,20 +122,13 @@ STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind,
mp_call_function_0(module_fun);
}

#ifndef _WIN32
// disable signal handler
sigaction(SIGINT, &sa, NULL);
#endif

mp_hal_set_interrupt_char(-1);
nlr_pop();
return 0;

} else {
// uncaught exception
#ifndef _WIN32
// disable signal handler
sigaction(SIGINT, &sa, NULL);
#endif
mp_hal_set_interrupt_char(-1);
return handle_uncaught_exception((mp_obj_t)nlr.ret_val);
}
}
Expand All @@ -177,7 +148,7 @@ STATIC char *strjoin(const char *s1, int sep_char, const char *s2) {
}

STATIC int do_repl(void) {
printf("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_PY_SYS_PLATFORM " version\n");
mp_hal_stdout_tx_str("Micro Python " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_PY_SYS_PLATFORM " version\n");

for (;;) {
char *line = prompt(">>> ");
Expand Down Expand Up @@ -306,9 +277,8 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
#define PATHLIST_SEP_CHAR ':'
#endif

#include <unistd.h>
int main(int argc, char **argv) {
prompt_read_history();

mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4));

pre_process_options(argc, argv);
Expand All @@ -318,8 +288,11 @@ int main(int argc, char **argv) {
gc_init(heap, heap + heap_size);
#endif

mp_hal_init();
mp_init();

prompt_read_history();

#ifndef _WIN32
// create keyboard interrupt object
MP_STATE_VM(keyboard_interrupt_obj) = mp_obj_new_exception(&mp_type_KeyboardInterrupt);
Expand Down Expand Up @@ -483,7 +456,10 @@ int main(int argc, char **argv) {
}
#endif

prompt_write_history();

mp_deinit();
mp_hal_deinit();

#if MICROPY_ENABLE_GC && !defined(NDEBUG)
// We don't really need to free memory since we are about to exit the
Expand All @@ -492,7 +468,6 @@ int main(int argc, char **argv) {
#endif

//printf("total bytes = %d\n", m_get_total_bytes_allocated());
prompt_write_history();
return ret & 0xff;
}

Expand Down
5 changes: 5 additions & 0 deletions unix/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,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>
Expand Down
3 changes: 0 additions & 3 deletions unix/mpconfigport.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
# Build 32-bit binaries on a 64-bit host
MICROPY_FORCE_32BIT = 0

# Linking with GNU readline causes binary to be licensed under GPL
MICROPY_USE_READLINE = 1

# Subset of CPython time module
MICROPY_PY_TIME = 1

Expand Down
Loading