From de48a27d607f0e7acbcbd841a8a4c685574114dc Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 7 Feb 2017 02:13:01 +0300 Subject: unix/main: Properly handle MICROPYPATH starting with ':'. In other words, where first path component is an empty string. --- unix/main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'unix/main.c') diff --git a/unix/main.c b/unix/main.c index f67c257cd..ad654780d 100644 --- a/unix/main.c +++ b/unix/main.c @@ -428,6 +428,9 @@ MP_NOINLINE int main_(int argc, char **argv) { #endif } mp_uint_t path_num = 1; // [0] is for current dir (or base dir of the script) + if (*path == ':') { + path_num++; + } for (char *p = path; p != NULL; p = strchr(p, PATHLIST_SEP_CHAR)) { path_num++; if (p != NULL) { -- cgit v1.2.3 From 5e83a75c78dc8c370b25e7ee669295854ea45130 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 3 Mar 2017 17:55:40 +1100 Subject: unix: Remove remaining, obsolete traces of GNU readline support. --- unix/input.c | 14 -------------- unix/main.c | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'unix/main.c') diff --git a/unix/input.c b/unix/input.c index 15ee60e75..7cd527fed 100644 --- a/unix/input.c +++ b/unix/input.c @@ -35,10 +35,6 @@ #if MICROPY_USE_READLINE == 1 #include "lib/mp-readline/readline.h" -#elif MICROPY_USE_READLINE == 2 -#include -#include -#include #endif char *prompt(char *p) { @@ -66,12 +62,6 @@ char *prompt(char *p) { 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]; @@ -124,8 +114,6 @@ void prompt_read_history(void) { } vstr_clear(&vstr); } - #elif MICROPY_USE_READLINE == 2 - read_history(tilde_expand("~/.micropython.history")); #endif #endif } @@ -152,8 +140,6 @@ void prompt_write_history(void) { close(fd); } } - #elif MICROPY_USE_READLINE == 2 - write_history(tilde_expand("~/.micropython.history")); #endif #endif } diff --git a/unix/main.c b/unix/main.c index ad654780d..d916cdeb8 100644 --- a/unix/main.c +++ b/unix/main.c @@ -249,7 +249,7 @@ STATIC int do_repl(void) { #else - // use GNU or simple readline + // use simple readline for (;;) { char *line = prompt(">>> "); -- cgit v1.2.3 From 33a77ea25f1959cb21789d7e1677753d8b7f9179 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 14 Mar 2017 11:23:54 +1100 Subject: unix/main: Refactor to put lexer constructors all in one place. The lexer can now raise an exception on construction so it must go within an nlr handler block. --- unix/main.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'unix/main.c') diff --git a/unix/main.c b/unix/main.c index d916cdeb8..01ebdce17 100644 --- a/unix/main.c +++ b/unix/main.c @@ -90,19 +90,33 @@ STATIC int handle_uncaught_exception(mp_obj_base_t *exc) { return 1; } +#define LEX_SRC_STR (1) +#define LEX_SRC_VSTR (2) +#define LEX_SRC_FILENAME (3) +#define LEX_SRC_STDIN (4) + // Returns standard error codes: 0 for success, 1 for all other errors, // except if FORCED_EXIT bit is set then script raised SystemExit and the // value of the exit is in the lower 8 bits of the return value -STATIC int execute_from_lexer(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) { - if (lex == NULL) { - printf("MemoryError: lexer could not allocate memory\n"); - return 1; - } - +STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) { mp_hal_set_interrupt_char(CHAR_CTRL_C); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { + // create lexer based on source kind + mp_lexer_t *lex; + if (source_kind == LEX_SRC_STR) { + const char *line = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); + } else if (source_kind == LEX_SRC_VSTR) { + const vstr_t *vstr = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false); + } else if (source_kind == LEX_SRC_FILENAME) { + lex = mp_lexer_new_from_file((const char*)source); + } else { // LEX_SRC_STDIN + lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); + } + qstr source_name = lex->source_name; #if MICROPY_PY___FILE__ @@ -240,8 +254,7 @@ STATIC int do_repl(void) { mp_hal_stdio_mode_orig(); - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line.buf, line.len, false); - ret = execute_from_lexer(lex, parse_input_kind, true); + ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true); if (ret & FORCED_EXIT) { return ret; } @@ -268,8 +281,7 @@ STATIC int do_repl(void) { line = line3; } - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); - int ret = execute_from_lexer(lex, MP_PARSE_SINGLE_INPUT, true); + int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true); if (ret & FORCED_EXIT) { return ret; } @@ -280,13 +292,11 @@ STATIC int do_repl(void) { } STATIC int do_file(const char *file) { - mp_lexer_t *lex = mp_lexer_new_from_file(file); - return execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); + return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false); } STATIC int do_str(const char *str) { - mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, str, strlen(str), false); - return execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); + return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false); } STATIC int usage(char **argv) { @@ -585,8 +595,7 @@ MP_NOINLINE int main_(int argc, char **argv) { ret = do_repl(); prompt_write_history(); } else { - mp_lexer_t *lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); - ret = execute_from_lexer(lex, MP_PARSE_FILE_INPUT, false); + ret = execute_from_lexer(LEX_SRC_STDIN, NULL, MP_PARSE_FILE_INPUT, false); } } -- cgit v1.2.3 From 46e98d9ea7daddb9650c91a6f4baf94c5ea18959 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 25 Mar 2017 19:37:24 +1100 Subject: unix: Convert mp_uint_t to size_t for use of mp_obj_list_get. --- unix/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'unix/main.c') diff --git a/unix/main.c b/unix/main.c index 01ebdce17..a1c204cab 100644 --- a/unix/main.c +++ b/unix/main.c @@ -437,7 +437,7 @@ MP_NOINLINE int main_(int argc, char **argv) { path = "~/.micropython/lib:/usr/lib/micropython"; #endif } - mp_uint_t path_num = 1; // [0] is for current dir (or base dir of the script) + size_t path_num = 1; // [0] is for current dir (or base dir of the script) if (*path == ':') { path_num++; } -- cgit v1.2.3 From 6c564aa408faf5d2769785b7ffc438a489310c3b Mon Sep 17 00:00:00 2001 From: Damien George Date: Mon, 10 Apr 2017 17:17:22 +1000 Subject: unix, windows: Use core-provided KeyboardInterrupt exception object. --- unix/main.c | 3 --- unix/mpconfigport.h | 2 +- unix/mpconfigport_minimal.h | 2 +- unix/unix_mphal.c | 10 +++++----- windows/mpconfigport.h | 4 ++-- windows/windows_mphal.c | 6 +++--- 6 files changed, 12 insertions(+), 15 deletions(-) (limited to 'unix/main.c') diff --git a/unix/main.c b/unix/main.c index a1c204cab..edea7900d 100644 --- a/unix/main.c +++ b/unix/main.c @@ -425,9 +425,6 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_init(); - // create keyboard interrupt object - MP_STATE_VM(keyboard_interrupt_obj) = mp_obj_new_exception(&mp_type_KeyboardInterrupt); - char *home = getenv("HOME"); char *path = getenv("MICROPYPATH"); if (path == NULL) { diff --git a/unix/mpconfigport.h b/unix/mpconfigport.h index 7ecfc28c0..4067e1950 100644 --- a/unix/mpconfigport.h +++ b/unix/mpconfigport.h @@ -156,6 +156,7 @@ #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256) +#define MICROPY_KBD_EXCEPTION (1) #define MICROPY_ASYNC_KBD_INTR (1) extern const struct _mp_obj_module_t mp_module_machine; @@ -283,7 +284,6 @@ void mp_unix_mark_exec(void); #define MICROPY_PORT_ROOT_POINTERS \ const char *readline_hist[50]; \ - mp_obj_t keyboard_interrupt_obj; \ void *mmap_region_head; \ // We need to provide a declaration/definition of alloca() diff --git a/unix/mpconfigport_minimal.h b/unix/mpconfigport_minimal.h index 788c8519d..b4d9f8143 100644 --- a/unix/mpconfigport_minimal.h +++ b/unix/mpconfigport_minimal.h @@ -47,6 +47,7 @@ #define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE) #define MICROPY_WARNINGS (0) #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) +#define MICROPY_KBD_EXCEPTION (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_NONE) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_NONE) #define MICROPY_STREAMS_NON_BLOCK (0) @@ -99,7 +100,6 @@ extern const struct _mp_obj_module_t mp_module_os; { MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&mp_module_os }, \ #define MICROPY_PORT_ROOT_POINTERS \ - mp_obj_t keyboard_interrupt_obj; ////////////////////////////////////////// // Do not change anything beyond this line diff --git a/unix/unix_mphal.c b/unix/unix_mphal.c index 6c6666236..800484498 100644 --- a/unix/unix_mphal.c +++ b/unix/unix_mphal.c @@ -40,20 +40,20 @@ STATIC void sighandler(int signum) { if (signum == SIGINT) { #if MICROPY_ASYNC_KBD_INTR - mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj)); + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); sigset_t mask; sigemptyset(&mask); // On entry to handler, its signal is blocked, and unblocked on // normal exit. As we instead perform longjmp, unblock it manually. sigprocmask(SIG_SETMASK, &mask, NULL); - nlr_raise(MP_STATE_VM(keyboard_interrupt_obj)); + nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); #else - if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) { + if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) { // 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); + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); #endif } } diff --git a/windows/mpconfigport.h b/windows/mpconfigport.h index 844e2618f..b91662af4 100644 --- a/windows/mpconfigport.h +++ b/windows/mpconfigport.h @@ -104,6 +104,7 @@ #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) #define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256) +#define MICROPY_KBD_EXCEPTION (1) #define MICROPY_PORT_INIT_FUNC init() #define MICROPY_PORT_DEINIT_FUNC deinit() @@ -161,8 +162,7 @@ extern const struct _mp_obj_module_t mp_module_time; #if MICROPY_USE_READLINE == 1 #define MICROPY_PORT_ROOT_POINTERS \ - char *readline_hist[50]; \ - mp_obj_t keyboard_interrupt_obj; + char *readline_hist[50]; #endif #define MP_STATE_PORT MP_STATE_VM diff --git a/windows/windows_mphal.c b/windows/windows_mphal.c index 3ad693905..1dd3105d8 100644 --- a/windows/windows_mphal.c +++ b/windows/windows_mphal.c @@ -79,12 +79,12 @@ void mp_hal_stdio_mode_orig(void) { // the thread created for handling it might not be running yet so we'd miss the notification. BOOL WINAPI console_sighandler(DWORD evt) { if (evt == CTRL_C_EVENT) { - if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) { + if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) { // 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); + mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))); + MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)); return TRUE; } return FALSE; -- cgit v1.2.3 From 11bc21dfa8f087ae2d95f378267ef270a85029ad Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Mon, 1 May 2017 18:47:26 +0300 Subject: unix/main: Ignore SIGPIPE signal, instead make EPIPE arrive. Do not raise SIGPIPE, instead return EPIPE. Otherwise, e.g. writing to peer-closed socket will lead to sudden termination of MicroPython process. SIGPIPE is particularly nasty, because unix shell doesn't print anything for it, so the above looks like completely sudden and silent termination for unknown reason. Ignoring SIGPIPE is also what CPython does. Note that this may lead to problems using MicroPython scripts as pipe filters, but again, that's what CPython does. So, scripts which want to follow unix shell pipe semantics (where SIGPIPE means "pipe was requested to terminate, it's not an error"), should catch EPIPE themselves. --- unix/main.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'unix/main.c') diff --git a/unix/main.c b/unix/main.c index edea7900d..84570eb9f 100644 --- a/unix/main.c +++ b/unix/main.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "py/mpstate.h" #include "py/nlr.h" @@ -414,6 +415,20 @@ int main(int argc, char **argv) { } MP_NOINLINE int main_(int argc, char **argv) { + #ifdef SIGPIPE + // Do not raise SIGPIPE, instead return EPIPE. Otherwise, e.g. writing + // to peer-closed socket will lead to sudden termination of MicroPython + // process. SIGPIPE is particularly nasty, because unix shell doesn't + // print anything for it, so the above looks like completely sudden and + // silent termination for unknown reason. Ignoring SIGPIPE is also what + // CPython does. Note that this may lead to problems using MicroPython + // scripts as pipe filters, but again, that's what CPython does. So, + // scripts which want to follow unix shell pipe semantics (where SIGPIPE + // means "pipe was requested to terminate, it's not an error"), should + // catch EPIPE themselves. + signal(SIGPIPE, SIG_IGN); + #endif + mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4)); pre_process_options(argc, argv); -- cgit v1.2.3 From c1e0eb7afe2109a81f6e3ec28f9d01705010500c Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 6 May 2017 11:40:20 +0300 Subject: unix/main: Don't allow to specify too small heap size. This will lead to crash like: FATAL: uncaught NLR 80a5420 On x86_32, the minimum heap size is smaller, but not 2 times, so just use value which works for x86_64. --- unix/main.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'unix/main.c') diff --git a/unix/main.c b/unix/main.c index 84570eb9f..93156d66e 100644 --- a/unix/main.c +++ b/unix/main.c @@ -375,6 +375,10 @@ STATIC void pre_process_options(int argc, char **argv) { if (word_adjust) { heap_size = heap_size * BYTES_PER_WORD / 4; } + // If requested size too small, we'll crash anyway + if (heap_size < 700) { + goto invalid_arg; + } #endif } else { invalid_arg: -- cgit v1.2.3 From edc02bd952ed4a2042f81b0eaa41f0168ed3d98d Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Tue, 9 May 2017 14:22:21 +0300 Subject: unix/main: Implement -m option for packages. --- py/builtinimport.c | 9 +++++++-- unix/main.c | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'unix/main.c') diff --git a/py/builtinimport.c b/py/builtinimport.c index cf17d5305..d01ebbe73 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -429,8 +429,13 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { // if args[3] (fromtuple) has magic value False, set up // this module for command-line "-m" option (set module's - // name to __main__ instead of real name). - if (i == mod_len && fromtuple == mp_const_false) { + // name to __main__ instead of real name). Do this only + // for *modules* however - packages never have their names + // replaced, instead they're -m'ed using a special __main__ + // submodule in them. (This all apparently is done to not + // touch package name itself, which is important for future + // imports). + if (i == mod_len && fromtuple == mp_const_false && stat != MP_IMPORT_STAT_DIR) { mp_obj_module_t *o = MP_OBJ_TO_PTR(module_obj); mp_obj_dict_store(MP_OBJ_FROM_PTR(o->globals), MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); #if MICROPY_CPYTHON_COMPAT diff --git a/unix/main.c b/unix/main.c index 93156d66e..633144c86 100644 --- a/unix/main.c +++ b/unix/main.c @@ -553,6 +553,9 @@ MP_NOINLINE int main_(int argc, char **argv) { mp_obj_t mod; nlr_buf_t nlr; + bool subpkg_tried = false; + + reimport: if (nlr_push(&nlr) == 0) { mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args); nlr_pop(); @@ -561,11 +564,17 @@ MP_NOINLINE int main_(int argc, char **argv) { return handle_uncaught_exception(nlr.ret_val) & 0xff; } - if (mp_obj_is_package(mod)) { - // TODO - mp_printf(&mp_stderr_print, "%s: -m for packages not yet implemented\n", argv[0]); - exit(1); + if (mp_obj_is_package(mod) && !subpkg_tried) { + subpkg_tried = true; + vstr_t vstr; + int len = strlen(argv[a + 1]); + vstr_init(&vstr, len + sizeof(".__main__")); + vstr_add_strn(&vstr, argv[a + 1], len); + vstr_add_strn(&vstr, ".__main__", sizeof(".__main__") - 1); + import_args[0] = mp_obj_new_str_from_vstr(&mp_type_str, &vstr); + goto reimport; } + ret = 0; break; } else if (strcmp(argv[a], "-X") == 0) { -- cgit v1.2.3