LCOV - code coverage report
Current view: top level - ports/unix - main.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-740-gbf49a087b.info Lines: 225 305 73.8 %
Date: 2022-12-09 11:55:04 Functions: 11 14 78.6 %
Branches: 102 156 65.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2013, 2014 Damien P. George
       7                 :            :  * Copyright (c) 2014-2017 Paul Sokolovsky
       8                 :            :  *
       9                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      10                 :            :  * of this software and associated documentation files (the "Software"), to deal
      11                 :            :  * in the Software without restriction, including without limitation the rights
      12                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13                 :            :  * copies of the Software, and to permit persons to whom the Software is
      14                 :            :  * furnished to do so, subject to the following conditions:
      15                 :            :  *
      16                 :            :  * The above copyright notice and this permission notice shall be included in
      17                 :            :  * all copies or substantial portions of the Software.
      18                 :            :  *
      19                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      25                 :            :  * THE SOFTWARE.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include <stdint.h>
      29                 :            : #include <stdbool.h>
      30                 :            : #include <stdio.h>
      31                 :            : #include <string.h>
      32                 :            : #include <stdlib.h>
      33                 :            : #include <stdarg.h>
      34                 :            : #include <unistd.h>
      35                 :            : #include <ctype.h>
      36                 :            : #include <sys/stat.h>
      37                 :            : #include <sys/types.h>
      38                 :            : #include <errno.h>
      39                 :            : #include <signal.h>
      40                 :            : 
      41                 :            : #include "py/compile.h"
      42                 :            : #include "py/runtime.h"
      43                 :            : #include "py/builtin.h"
      44                 :            : #include "py/repl.h"
      45                 :            : #include "py/gc.h"
      46                 :            : #include "py/objstr.h"
      47                 :            : #include "py/stackctrl.h"
      48                 :            : #include "py/mphal.h"
      49                 :            : #include "py/mpthread.h"
      50                 :            : #include "extmod/misc.h"
      51                 :            : #include "extmod/moduplatform.h"
      52                 :            : #include "extmod/vfs.h"
      53                 :            : #include "extmod/vfs_posix.h"
      54                 :            : #include "genhdr/mpversion.h"
      55                 :            : #include "input.h"
      56                 :            : 
      57                 :            : // Command line options, with their defaults
      58                 :            : STATIC bool compile_only = false;
      59                 :            : STATIC uint emit_opt = MP_EMIT_OPT_NONE;
      60                 :            : 
      61                 :            : #if MICROPY_ENABLE_GC
      62                 :            : // Heap size of GC heap (if enabled)
      63                 :            : // Make it larger on a 64 bit machine, because pointers are larger.
      64                 :            : long heap_size = 1024 * 1024 * (sizeof(mp_uint_t) / 4);
      65                 :            : #endif
      66                 :            : 
      67                 :            : // Number of heaps to assign by default if MICROPY_GC_SPLIT_HEAP=1
      68                 :            : #ifndef MICROPY_GC_SPLIT_HEAP_N_HEAPS
      69                 :            : #define MICROPY_GC_SPLIT_HEAP_N_HEAPS (1)
      70                 :            : #endif
      71                 :            : 
      72                 :         66 : STATIC void stderr_print_strn(void *env, const char *str, size_t len) {
      73                 :         66 :     (void)env;
      74                 :         66 :     ssize_t ret;
      75   [ -  +  -  - ]:         66 :     MP_HAL_RETRY_SYSCALL(ret, write(STDERR_FILENO, str, len), {});
      76                 :         66 :     mp_uos_dupterm_tx_strn(str, len);
      77                 :         66 : }
      78                 :            : 
      79                 :            : const mp_print_t mp_stderr_print = {NULL, stderr_print_strn};
      80                 :            : 
      81                 :            : #define FORCED_EXIT (0x100)
      82                 :            : // If exc is SystemExit, return value where FORCED_EXIT bit set,
      83                 :            : // and lower 8 bits are SystemExit value. For all other exceptions,
      84                 :            : // return 1.
      85                 :         17 : STATIC int handle_uncaught_exception(mp_obj_base_t *exc) {
      86                 :            :     // check for SystemExit
      87         [ +  - ]:         17 :     if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exc->type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) {
      88                 :            :         // None is an exit value of 0; an int is its value; anything else is 1
      89                 :         17 :         mp_obj_t exit_val = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(exc));
      90                 :         17 :         mp_int_t val = 0;
      91   [ -  +  -  - ]:         17 :         if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) {
      92                 :          0 :             val = 1;
      93                 :            :         }
      94                 :         17 :         return FORCED_EXIT | (val & 255);
      95                 :            :     }
      96                 :            : 
      97                 :            :     // Report all other exceptions
      98                 :          0 :     mp_obj_print_exception(&mp_stderr_print, MP_OBJ_FROM_PTR(exc));
      99                 :          0 :     return 1;
     100                 :            : }
     101                 :            : 
     102                 :            : #define LEX_SRC_STR (1)
     103                 :            : #define LEX_SRC_VSTR (2)
     104                 :            : #define LEX_SRC_FILENAME (3)
     105                 :            : #define LEX_SRC_STDIN (4)
     106                 :            : 
     107                 :            : // Returns standard error codes: 0 for success, 1 for all other errors,
     108                 :            : // except if FORCED_EXIT bit is set then script raised SystemExit and the
     109                 :            : // value of the exit is in the lower 8 bits of the return value
     110                 :       2096 : STATIC int execute_from_lexer(int source_kind, const void *source, mp_parse_input_kind_t input_kind, bool is_repl) {
     111                 :       2096 :     mp_hal_set_interrupt_char(CHAR_CTRL_C);
     112                 :            : 
     113                 :       2096 :     nlr_buf_t nlr;
     114         [ +  + ]:       2096 :     if (nlr_push(&nlr) == 0) {
     115                 :            :         // create lexer based on source kind
     116                 :       2096 :         mp_lexer_t *lex;
     117         [ +  + ]:       2096 :         if (source_kind == LEX_SRC_STR) {
     118                 :          2 :             const char *line = source;
     119                 :          2 :             lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false);
     120         [ +  + ]:       2094 :         } else if (source_kind == LEX_SRC_VSTR) {
     121                 :        211 :             const vstr_t *vstr = source;
     122                 :        211 :             lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false);
     123         [ +  + ]:       1883 :         } else if (source_kind == LEX_SRC_FILENAME) {
     124                 :       1882 :             lex = mp_lexer_new_from_file((const char *)source);
     125                 :            :         } else { // LEX_SRC_STDIN
     126                 :          1 :             lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false);
     127                 :            :         }
     128                 :            : 
     129                 :       2096 :         qstr source_name = lex->source_name;
     130                 :            : 
     131                 :            :         #if MICROPY_PY___FILE__
     132         [ +  + ]:       2096 :         if (input_kind == MP_PARSE_FILE_INPUT) {
     133                 :       1885 :             mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name));
     134                 :            :         }
     135                 :            :         #endif
     136                 :            : 
     137                 :       2096 :         mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
     138                 :            : 
     139                 :            :         #if defined(MICROPY_UNIX_COVERAGE)
     140                 :            :         // allow to print the parse tree in the coverage build
     141         [ +  + ]:       2096 :         if (mp_verbose_flag >= 3) {
     142                 :          2 :             printf("----------------\n");
     143                 :          2 :             mp_parse_node_print(&mp_plat_print, parse_tree.root, 0);
     144                 :          2 :             printf("----------------\n");
     145                 :            :         }
     146                 :            :         #endif
     147                 :            : 
     148                 :       2096 :         mp_obj_t module_fun = mp_compile(&parse_tree, source_name, is_repl);
     149                 :            : 
     150         [ +  - ]:       2096 :         if (!compile_only) {
     151                 :            :             // execute it
     152                 :       2096 :             mp_call_function_0(module_fun);
     153                 :            :         }
     154                 :            : 
     155                 :       2083 :         mp_hal_set_interrupt_char(-1);
     156                 :       2083 :         mp_handle_pending(true);
     157                 :       2083 :         nlr_pop();
     158                 :       2083 :         return 0;
     159                 :            : 
     160                 :            :     } else {
     161                 :            :         // uncaught exception
     162                 :         13 :         mp_hal_set_interrupt_char(-1);
     163                 :         13 :         mp_handle_pending(false);
     164                 :         13 :         return handle_uncaught_exception(nlr.ret_val);
     165                 :            :     }
     166                 :            : }
     167                 :            : 
     168                 :            : #if MICROPY_USE_READLINE == 1
     169                 :            : #include "shared/readline/readline.h"
     170                 :            : #else
     171                 :            : STATIC char *strjoin(const char *s1, int sep_char, const char *s2) {
     172                 :            :     int l1 = strlen(s1);
     173                 :            :     int l2 = strlen(s2);
     174                 :            :     char *s = malloc(l1 + l2 + 2);
     175                 :            :     memcpy(s, s1, l1);
     176                 :            :     if (sep_char != 0) {
     177                 :            :         s[l1] = sep_char;
     178                 :            :         l1 += 1;
     179                 :            :     }
     180                 :            :     memcpy(s + l1, s2, l2);
     181                 :            :     s[l1 + l2] = 0;
     182                 :            :     return s;
     183                 :            : }
     184                 :            : #endif
     185                 :            : 
     186                 :         28 : STATIC int do_repl(void) {
     187                 :         28 :     mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION);
     188                 :         28 :     mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE);
     189                 :         28 :     mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n");
     190                 :            : 
     191                 :            :     #if MICROPY_USE_READLINE == 1
     192                 :            : 
     193                 :            :     // use MicroPython supplied readline
     194                 :            : 
     195                 :         28 :     vstr_t line;
     196                 :         28 :     vstr_init(&line, 16);
     197                 :        239 :     for (;;) {
     198                 :        239 :         mp_hal_stdio_mode_raw();
     199                 :            : 
     200                 :         10 :     input_restart:
     201                 :        249 :         vstr_reset(&line);
     202                 :        249 :         int ret = readline(&line, mp_repl_get_ps1());
     203                 :        249 :         mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT;
     204                 :            : 
     205         [ -  + ]:        249 :         if (ret == CHAR_CTRL_C) {
     206                 :            :             // cancel input
     207                 :          0 :             mp_hal_stdout_tx_str("\r\n");
     208                 :          0 :             goto input_restart;
     209         [ +  + ]:        249 :         } else if (ret == CHAR_CTRL_D) {
     210                 :            :             // EOF
     211                 :         28 :             printf("\n");
     212                 :         28 :             mp_hal_stdio_mode_orig();
     213                 :         28 :             vstr_clear(&line);
     214                 :         28 :             return 0;
     215         [ -  + ]:        221 :         } else if (ret == CHAR_CTRL_E) {
     216                 :            :             // paste mode
     217                 :          0 :             mp_hal_stdout_tx_str("\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== ");
     218                 :          0 :             vstr_reset(&line);
     219                 :          0 :             for (;;) {
     220                 :          0 :                 char c = mp_hal_stdin_rx_chr();
     221         [ #  # ]:          0 :                 if (c == CHAR_CTRL_C) {
     222                 :            :                     // cancel everything
     223                 :          0 :                     mp_hal_stdout_tx_str("\n");
     224                 :          0 :                     goto input_restart;
     225         [ #  # ]:          0 :                 } else if (c == CHAR_CTRL_D) {
     226                 :            :                     // end of input
     227                 :          0 :                     mp_hal_stdout_tx_str("\n");
     228                 :          0 :                     break;
     229                 :            :                 } else {
     230                 :            :                     // add char to buffer and echo
     231                 :          0 :                     vstr_add_byte(&line, c);
     232         [ #  # ]:          0 :                     if (c == '\r') {
     233                 :          0 :                         mp_hal_stdout_tx_str("\n=== ");
     234                 :            :                     } else {
     235                 :          0 :                         mp_hal_stdout_tx_strn(&c, 1);
     236                 :            :                     }
     237                 :            :                 }
     238                 :            :             }
     239                 :          0 :             parse_input_kind = MP_PARSE_FILE_INPUT;
     240         [ +  + ]:        221 :         } else if (line.len == 0) {
     241         [ -  + ]:         10 :             if (ret != 0) {
     242                 :          0 :                 printf("\n");
     243                 :            :             }
     244                 :         10 :             goto input_restart;
     245                 :            :         } else {
     246                 :            :             // got a line with non-zero length, see if it needs continuing
     247         [ +  + ]:        253 :             while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) {
     248                 :         42 :                 vstr_add_byte(&line, '\n');
     249                 :         42 :                 ret = readline(&line, mp_repl_get_ps2());
     250         [ -  + ]:         42 :                 if (ret == CHAR_CTRL_C) {
     251                 :            :                     // cancel everything
     252                 :          0 :                     printf("\n");
     253                 :          0 :                     goto input_restart;
     254         [ +  - ]:         42 :                 } else if (ret == CHAR_CTRL_D) {
     255                 :            :                     // stop entering compound statement
     256                 :            :                     break;
     257                 :            :                 }
     258                 :            :             }
     259                 :            :         }
     260                 :            : 
     261                 :        211 :         mp_hal_stdio_mode_orig();
     262                 :            : 
     263                 :        211 :         ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true);
     264         [ +  - ]:        211 :         if (ret & FORCED_EXIT) {
     265                 :            :             return ret;
     266                 :            :         }
     267                 :            :     }
     268                 :            : 
     269                 :            :     #else
     270                 :            : 
     271                 :            :     // use simple readline
     272                 :            : 
     273                 :            :     for (;;) {
     274                 :            :         char *line = prompt((char *)mp_repl_get_ps1());
     275                 :            :         if (line == NULL) {
     276                 :            :             // EOF
     277                 :            :             return 0;
     278                 :            :         }
     279                 :            :         while (mp_repl_continue_with_input(line)) {
     280                 :            :             char *line2 = prompt((char *)mp_repl_get_ps2());
     281                 :            :             if (line2 == NULL) {
     282                 :            :                 break;
     283                 :            :             }
     284                 :            :             char *line3 = strjoin(line, '\n', line2);
     285                 :            :             free(line);
     286                 :            :             free(line2);
     287                 :            :             line = line3;
     288                 :            :         }
     289                 :            : 
     290                 :            :         int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true);
     291                 :            :         if (ret & FORCED_EXIT) {
     292                 :            :             return ret;
     293                 :            :         }
     294                 :            :         free(line);
     295                 :            :     }
     296                 :            : 
     297                 :            :     #endif
     298                 :            : }
     299                 :            : 
     300                 :       1882 : STATIC int do_file(const char *file) {
     301                 :       1882 :     return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false);
     302                 :            : }
     303                 :            : 
     304                 :          2 : STATIC int do_str(const char *str) {
     305                 :          2 :     return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false);
     306                 :            : }
     307                 :            : 
     308                 :          0 : STATIC void print_help(char **argv) {
     309                 :          0 :     printf(
     310                 :            :         "usage: %s [<opts>] [-X <implopt>] [-c <command> | -m <module> | <filename>]\n"
     311                 :            :         "Options:\n"
     312                 :            :         "-h : print this help message\n"
     313                 :            :         "-i : enable inspection via REPL after running command/module/file\n"
     314                 :            :         #if MICROPY_DEBUG_PRINTERS
     315                 :            :         "-v : verbose (trace various operations); can be multiple\n"
     316                 :            :         #endif
     317                 :            :         "-O[N] : apply bytecode optimizations of level N\n"
     318                 :            :         "\n"
     319                 :            :         "Implementation specific options (-X):\n", argv[0]
     320                 :            :         );
     321                 :          0 :     int impl_opts_cnt = 0;
     322                 :          0 :     printf(
     323                 :            :         "  compile-only                 -- parse and compile only\n"
     324                 :            :         #if MICROPY_EMIT_NATIVE
     325                 :            :         "  emit={bytecode,native,viper} -- set the default code emitter\n"
     326                 :            :         #else
     327                 :            :         "  emit=bytecode                -- set the default code emitter\n"
     328                 :            :         #endif
     329                 :            :         );
     330                 :          0 :     impl_opts_cnt++;
     331                 :            :     #if MICROPY_ENABLE_GC
     332                 :          0 :     printf(
     333                 :            :         "  heapsize=<n>[w][K|M] -- set the heap size for the GC (default %ld)\n"
     334                 :            :         , heap_size);
     335                 :          0 :     impl_opts_cnt++;
     336                 :            :     #endif
     337                 :            :     #if defined(__APPLE__)
     338                 :            :     printf("  realtime -- set thread priority to realtime\n");
     339                 :            :     impl_opts_cnt++;
     340                 :            :     #endif
     341                 :            : 
     342                 :          0 :     if (impl_opts_cnt == 0) {
     343                 :            :         printf("  (none)\n");
     344                 :            :     }
     345                 :          0 : }
     346                 :            : 
     347                 :          0 : STATIC int invalid_args(void) {
     348                 :          0 :     fprintf(stderr, "Invalid command line arguments. Use -h option for help.\n");
     349                 :          0 :     return 1;
     350                 :            : }
     351                 :            : 
     352                 :            : // Process options which set interpreter init options
     353                 :       3206 : STATIC void pre_process_options(int argc, char **argv) {
     354         [ +  + ]:       6314 :     for (int a = 1; a < argc; a++) {
     355         [ +  + ]:       6289 :         if (argv[a][0] == '-') {
     356   [ +  +  +  + ]:       4407 :             if (strcmp(argv[a], "-c") == 0 || strcmp(argv[a], "-m") == 0) {
     357                 :            :                 break; // Everything after this is a command/module and arguments for it
     358                 :            :             }
     359         [ -  + ]:       3108 :             if (strcmp(argv[a], "-h") == 0) {
     360                 :          0 :                 print_help(argv);
     361                 :          0 :                 exit(0);
     362                 :            :             }
     363         [ +  + ]:       3108 :             if (strcmp(argv[a], "-X") == 0) {
     364         [ -  + ]:       3082 :                 if (a + 1 >= argc) {
     365                 :          0 :                     exit(invalid_args());
     366                 :            :                 }
     367                 :       3082 :                 if (0) {
     368         [ -  + ]:       3082 :                 } else if (strcmp(argv[a + 1], "compile-only") == 0) {
     369                 :          0 :                     compile_only = true;
     370         [ +  + ]:       3082 :                 } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) {
     371                 :       1579 :                     emit_opt = MP_EMIT_OPT_BYTECODE;
     372                 :            :                 #if MICROPY_EMIT_NATIVE
     373         [ +  - ]:       1503 :                 } else if (strcmp(argv[a + 1], "emit=native") == 0) {
     374                 :       1503 :                     emit_opt = MP_EMIT_OPT_NATIVE_PYTHON;
     375         [ #  # ]:          0 :                 } else if (strcmp(argv[a + 1], "emit=viper") == 0) {
     376                 :          0 :                     emit_opt = MP_EMIT_OPT_VIPER;
     377                 :            :                 #endif
     378                 :            :                 #if MICROPY_ENABLE_GC
     379         [ #  # ]:          0 :                 } else if (strncmp(argv[a + 1], "heapsize=", sizeof("heapsize=") - 1) == 0) {
     380                 :          0 :                     char *end;
     381                 :          0 :                     heap_size = strtol(argv[a + 1] + sizeof("heapsize=") - 1, &end, 0);
     382                 :            :                     // Don't bring unneeded libc dependencies like tolower()
     383                 :            :                     // If there's 'w' immediately after number, adjust it for
     384                 :            :                     // target word size. Note that it should be *before* size
     385                 :            :                     // suffix like K or M, to avoid confusion with kilowords,
     386                 :            :                     // etc. the size is still in bytes, just can be adjusted
     387                 :            :                     // for word size (taking 32bit as baseline).
     388                 :          0 :                     bool word_adjust = false;
     389         [ #  # ]:          0 :                     if ((*end | 0x20) == 'w') {
     390                 :          0 :                         word_adjust = true;
     391                 :          0 :                         end++;
     392                 :            :                     }
     393         [ #  # ]:          0 :                     if ((*end | 0x20) == 'k') {
     394                 :          0 :                         heap_size *= 1024;
     395         [ #  # ]:          0 :                     } else if ((*end | 0x20) == 'm') {
     396                 :          0 :                         heap_size *= 1024 * 1024;
     397                 :            :                     } else {
     398                 :            :                         // Compensate for ++ below
     399                 :          0 :                         --end;
     400                 :            :                     }
     401         [ #  # ]:          0 :                     if (*++end != 0) {
     402                 :          0 :                         goto invalid_arg;
     403                 :            :                     }
     404         [ #  # ]:          0 :                     if (word_adjust) {
     405                 :          0 :                         heap_size = heap_size * MP_BYTES_PER_OBJ_WORD / 4;
     406                 :            :                     }
     407                 :            :                     // If requested size too small, we'll crash anyway
     408         [ #  # ]:          0 :                     if (heap_size < 700) {
     409                 :          0 :                         goto invalid_arg;
     410                 :            :                     }
     411                 :            :                 #endif
     412                 :            :                 #if defined(__APPLE__)
     413                 :            :                 } else if (strcmp(argv[a + 1], "realtime") == 0) {
     414                 :            :                     #if MICROPY_PY_THREAD
     415                 :            :                     mp_thread_is_realtime_enabled = true;
     416                 :            :                     #endif
     417                 :            :                     // main thread was already intialized before the option
     418                 :            :                     // was parsed, so we have to enable realtime here.
     419                 :            :                     mp_thread_set_realtime();
     420                 :            :                 #endif
     421                 :            :                 } else {
     422                 :          0 :                 invalid_arg:
     423                 :          0 :                     exit(invalid_args());
     424                 :            :                 }
     425                 :            :                 a++;
     426                 :            :             }
     427                 :            :         } else {
     428                 :            :             break; // Not an option but a file
     429                 :            :         }
     430                 :            :     }
     431                 :       3206 : }
     432                 :            : 
     433                 :       3183 : STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
     434         [ +  + ]:       6364 :     for (int i = start_arg; i < argc; i++) {
     435                 :       3181 :         mp_obj_list_append(mp_sys_argv, MP_OBJ_NEW_QSTR(qstr_from_str(argv[i])));
     436                 :            :     }
     437                 :       3183 : }
     438                 :            : 
     439                 :            : #if MICROPY_PY_SYS_EXECUTABLE
     440                 :            : extern mp_obj_str_t mp_sys_executable_obj;
     441                 :            : STATIC char executable_path[MICROPY_ALLOC_PATH_MAX];
     442                 :            : 
     443                 :       3206 : STATIC void sys_set_excecutable(char *argv0) {
     444         [ +  - ]:       3206 :     if (realpath(argv0, executable_path)) {
     445                 :       3206 :         mp_obj_str_set_data(&mp_sys_executable_obj, (byte *)executable_path, strlen(executable_path));
     446                 :            :     }
     447                 :       3206 : }
     448                 :            : #endif
     449                 :            : 
     450                 :            : #ifdef _WIN32
     451                 :            : #define PATHLIST_SEP_CHAR ';'
     452                 :            : #else
     453                 :            : #define PATHLIST_SEP_CHAR ':'
     454                 :            : #endif
     455                 :            : 
     456                 :            : MP_NOINLINE int main_(int argc, char **argv);
     457                 :            : 
     458                 :       3206 : int main(int argc, char **argv) {
     459                 :            :     #if MICROPY_PY_THREAD
     460                 :       3206 :     mp_thread_init();
     461                 :            :     #endif
     462                 :            :     // We should capture stack top ASAP after start, and it should be
     463                 :            :     // captured guaranteedly before any other stack variables are allocated.
     464                 :            :     // For this, actual main (renamed main_) should not be inlined into
     465                 :            :     // this function. main_() itself may have other functions inlined (with
     466                 :            :     // their own stack variables), that's why we need this main/main_ split.
     467                 :       3206 :     mp_stack_ctrl_init();
     468                 :       3206 :     return main_(argc, argv);
     469                 :            : }
     470                 :            : 
     471                 :       3206 : MP_NOINLINE int main_(int argc, char **argv) {
     472                 :            :     #ifdef SIGPIPE
     473                 :            :     // Do not raise SIGPIPE, instead return EPIPE. Otherwise, e.g. writing
     474                 :            :     // to peer-closed socket will lead to sudden termination of MicroPython
     475                 :            :     // process. SIGPIPE is particularly nasty, because unix shell doesn't
     476                 :            :     // print anything for it, so the above looks like completely sudden and
     477                 :            :     // silent termination for unknown reason. Ignoring SIGPIPE is also what
     478                 :            :     // CPython does. Note that this may lead to problems using MicroPython
     479                 :            :     // scripts as pipe filters, but again, that's what CPython does. So,
     480                 :            :     // scripts which want to follow unix shell pipe semantics (where SIGPIPE
     481                 :            :     // means "pipe was requested to terminate, it's not an error"), should
     482                 :            :     // catch EPIPE themselves.
     483                 :       3206 :     signal(SIGPIPE, SIG_IGN);
     484                 :            :     #endif
     485                 :            : 
     486                 :            :     // Define a reasonable stack limit to detect stack overflow.
     487                 :       3206 :     mp_uint_t stack_limit = 40000 * (sizeof(void *) / 4);
     488                 :            :     #if defined(__arm__) && !defined(__thumb2__)
     489                 :            :     // ARM (non-Thumb) architectures require more stack.
     490                 :            :     stack_limit *= 2;
     491                 :            :     #endif
     492                 :       3206 :     mp_stack_set_limit(stack_limit);
     493                 :            : 
     494                 :       3206 :     pre_process_options(argc, argv);
     495                 :            : 
     496                 :            :     #if MICROPY_ENABLE_GC
     497                 :            :     #if !MICROPY_GC_SPLIT_HEAP
     498                 :            :     char *heap = malloc(heap_size);
     499                 :            :     gc_init(heap, heap + heap_size);
     500                 :            :     #else
     501                 :       3206 :     assert(MICROPY_GC_SPLIT_HEAP_N_HEAPS > 0);
     502                 :       3206 :     char *heaps[MICROPY_GC_SPLIT_HEAP_N_HEAPS];
     503                 :       3206 :     long multi_heap_size = heap_size / MICROPY_GC_SPLIT_HEAP_N_HEAPS;
     504         [ +  + ]:      16030 :     for (size_t i = 0; i < MICROPY_GC_SPLIT_HEAP_N_HEAPS; i++) {
     505                 :      12824 :         heaps[i] = malloc(multi_heap_size);
     506         [ +  + ]:      12824 :         if (i == 0) {
     507                 :       3206 :             gc_init(heaps[i], heaps[i] + multi_heap_size);
     508                 :            :         } else {
     509                 :       9618 :             gc_add(heaps[i], heaps[i] + multi_heap_size);
     510                 :            :         }
     511                 :            :     }
     512                 :            :     #endif
     513                 :            :     #endif
     514                 :            : 
     515                 :            :     #if MICROPY_ENABLE_PYSTACK
     516                 :            :     static mp_obj_t pystack[1024];
     517                 :            :     mp_pystack_init(pystack, &pystack[MP_ARRAY_SIZE(pystack)]);
     518                 :            :     #endif
     519                 :            : 
     520                 :       3206 :     mp_init();
     521                 :            : 
     522                 :            :     #if MICROPY_EMIT_NATIVE
     523                 :            :     // Set default emitter options
     524                 :       3206 :     MP_STATE_VM(default_emit_opt) = emit_opt;
     525                 :            :     #else
     526                 :            :     (void)emit_opt;
     527                 :            :     #endif
     528                 :            : 
     529                 :            :     #if MICROPY_VFS_POSIX
     530                 :            :     {
     531                 :            :         // Mount the host FS at the root of our internal VFS
     532                 :       6412 :         mp_obj_t args[2] = {
     533                 :       3206 :             MP_OBJ_TYPE_GET_SLOT(&mp_type_vfs_posix, make_new)(&mp_type_vfs_posix, 0, 0, NULL),
     534                 :            :             MP_OBJ_NEW_QSTR(MP_QSTR__slash_),
     535                 :            :         };
     536                 :       3206 :         mp_vfs_mount(2, args, (mp_map_t *)&mp_const_empty_map);
     537                 :       3206 :         MP_STATE_VM(vfs_cur) = MP_STATE_VM(vfs_mount_table);
     538                 :            :     }
     539                 :            :     #endif
     540                 :            : 
     541                 :       3206 :     char *home = getenv("HOME");
     542                 :       3206 :     char *path = getenv("MICROPYPATH");
     543         [ +  + ]:       3206 :     if (path == NULL) {
     544                 :          1 :         path = MICROPY_PY_SYS_PATH_DEFAULT;
     545                 :            :     }
     546                 :       3206 :     size_t path_num = 1; // [0] is for current dir (or base dir of the script)
     547         [ -  + ]:       3206 :     if (*path == PATHLIST_SEP_CHAR) {
     548                 :          0 :         path_num++;
     549                 :            :     }
     550         [ +  + ]:       9619 :     for (char *p = path; p != NULL; p = strchr(p, PATHLIST_SEP_CHAR)) {
     551                 :       6413 :         path_num++;
     552                 :       6413 :         if (p != NULL) {
     553                 :       6413 :             p++;
     554                 :            :         }
     555                 :            :     }
     556                 :       3206 :     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), path_num);
     557                 :       3206 :     mp_obj_t *path_items;
     558                 :       3206 :     mp_obj_list_get(mp_sys_path, &path_num, &path_items);
     559                 :       3206 :     path_items[0] = MP_OBJ_NEW_QSTR(MP_QSTR_);
     560                 :            :     {
     561                 :       3206 :         char *p = path;
     562         [ +  + ]:       9619 :         for (mp_uint_t i = 1; i < path_num; i++) {
     563                 :       6413 :             char *p1 = strchr(p, PATHLIST_SEP_CHAR);
     564         [ +  + ]:       6413 :             if (p1 == NULL) {
     565                 :       3206 :                 p1 = p + strlen(p);
     566                 :            :             }
     567   [ +  +  +  -  :       6413 :             if (p[0] == '~' && p[1] == '/' && home != NULL) {
                   +  - ]
     568                 :            :                 // Expand standalone ~ to $HOME
     569                 :          1 :                 int home_l = strlen(home);
     570                 :          1 :                 vstr_t vstr;
     571                 :          1 :                 vstr_init(&vstr, home_l + (p1 - p - 1) + 1);
     572                 :          1 :                 vstr_add_strn(&vstr, home, home_l);
     573                 :          1 :                 vstr_add_strn(&vstr, p + 1, p1 - p - 1);
     574                 :          1 :                 path_items[i] = mp_obj_new_str_from_vstr(&vstr);
     575                 :            :             } else {
     576                 :       6412 :                 path_items[i] = mp_obj_new_str_via_qstr(p, p1 - p);
     577                 :            :             }
     578                 :       6413 :             p = p1 + 1;
     579                 :            :         }
     580                 :            :     }
     581                 :            : 
     582                 :       3206 :     mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
     583                 :            : 
     584                 :            :     #if defined(MICROPY_UNIX_COVERAGE)
     585                 :            :     {
     586                 :       3206 :         MP_DECLARE_CONST_FUN_OBJ_0(extra_coverage_obj);
     587                 :       3206 :         MP_DECLARE_CONST_FUN_OBJ_0(extra_cpp_coverage_obj);
     588                 :       3206 :         mp_store_global(MP_QSTR_extra_coverage, MP_OBJ_FROM_PTR(&extra_coverage_obj));
     589                 :       3206 :         mp_store_global(MP_QSTR_extra_cpp_coverage, MP_OBJ_FROM_PTR(&extra_cpp_coverage_obj));
     590                 :            :     }
     591                 :            :     #endif
     592                 :            : 
     593                 :            :     // Here is some example code to create a class and instance of that class.
     594                 :            :     // First is the Python, then the C code.
     595                 :            :     //
     596                 :            :     // class TestClass:
     597                 :            :     //     pass
     598                 :            :     // test_obj = TestClass()
     599                 :            :     // test_obj.attr = 42
     600                 :            :     //
     601                 :            :     // mp_obj_t test_class_type, test_class_instance;
     602                 :            :     // test_class_type = mp_obj_new_type(qstr_from_str("TestClass"), mp_const_empty_tuple, mp_obj_new_dict(0));
     603                 :            :     // mp_store_name(qstr_from_str("test_obj"), test_class_instance = mp_call_function_0(test_class_type));
     604                 :            :     // mp_store_attr(test_class_instance, qstr_from_str("attr"), mp_obj_new_int(42));
     605                 :            : 
     606                 :            :     /*
     607                 :            :     printf("bytes:\n");
     608                 :            :     printf("    total %d\n", m_get_total_bytes_allocated());
     609                 :            :     printf("    cur   %d\n", m_get_current_bytes_allocated());
     610                 :            :     printf("    peak  %d\n", m_get_peak_bytes_allocated());
     611                 :            :     */
     612                 :            : 
     613                 :            :     #if MICROPY_PY_SYS_EXECUTABLE
     614                 :       3206 :     sys_set_excecutable(argv[0]);
     615                 :            :     #endif
     616                 :            : 
     617                 :       3206 :     const int NOTHING_EXECUTED = -2;
     618                 :       3206 :     int ret = NOTHING_EXECUTED;
     619                 :       3206 :     bool inspect = false;
     620         [ +  + ]:       6314 :     for (int a = 1; a < argc; a++) {
     621         [ +  + ]:       6289 :         if (argv[a][0] == '-') {
     622         [ +  + ]:       4407 :             if (strcmp(argv[a], "-i") == 0) {
     623                 :            :                 inspect = true;
     624         [ +  + ]:       4405 :             } else if (strcmp(argv[a], "-c") == 0) {
     625         [ -  + ]:          2 :                 if (a + 1 >= argc) {
     626                 :          0 :                     return invalid_args();
     627                 :            :                 }
     628                 :          2 :                 set_sys_argv(argv, a + 1, a); // The -c becomes first item of sys.argv, as in CPython
     629                 :          2 :                 set_sys_argv(argv, argc, a + 2); // Then what comes after the command
     630                 :          2 :                 ret = do_str(argv[a + 1]);
     631                 :          2 :                 break;
     632         [ +  + ]:       4403 :             } else if (strcmp(argv[a], "-m") == 0) {
     633         [ -  + ]:       1297 :                 if (a + 1 >= argc) {
     634                 :          4 :                     return invalid_args();
     635                 :            :                 }
     636                 :       1297 :                 mp_obj_t import_args[4];
     637                 :       1297 :                 import_args[0] = mp_obj_new_str(argv[a + 1], strlen(argv[a + 1]));
     638                 :       1297 :                 import_args[1] = import_args[2] = mp_const_none;
     639                 :            :                 // Ask __import__ to handle imported module specially - set its __name__
     640                 :            :                 // to __main__, and also return this leaf module, not top-level package
     641                 :            :                 // containing it.
     642                 :       1297 :                 import_args[3] = mp_const_false;
     643                 :            :                 // TODO: https://docs.python.org/3/using/cmdline.html#cmdoption-m :
     644                 :            :                 // "the first element of sys.argv will be the full path to
     645                 :            :                 // the module file (while the module file is being located,
     646                 :            :                 // the first element will be set to "-m")."
     647                 :       1297 :                 set_sys_argv(argv, argc, a + 1);
     648                 :            : 
     649                 :       1297 :                 mp_obj_t mod;
     650                 :       1297 :                 nlr_buf_t nlr;
     651                 :            : 
     652                 :            :                 // Allocating subpkg_tried on the stack can lead to compiler warnings about this
     653                 :            :                 // variable being clobbered when nlr is implemented using setjmp/longjmp.  Its
     654                 :            :                 // value must be preserved across calls to setjmp/longjmp.
     655                 :       1297 :                 static bool subpkg_tried;
     656                 :       1297 :                 subpkg_tried = false;
     657                 :            : 
     658                 :       1297 :             reimport:
     659         [ +  + ]:       1297 :                 if (nlr_push(&nlr) == 0) {
     660                 :       1297 :                     mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args);
     661                 :       1293 :                     nlr_pop();
     662                 :            :                 } else {
     663                 :            :                     // uncaught exception
     664                 :          4 :                     return handle_uncaught_exception(nlr.ret_val) & 0xff;
     665                 :            :                 }
     666                 :            : 
     667   [ -  +  -  - ]:       1293 :                 if (mp_obj_is_package(mod) && !subpkg_tried) {
     668                 :          0 :                     subpkg_tried = true;
     669                 :          0 :                     vstr_t vstr;
     670                 :          0 :                     int len = strlen(argv[a + 1]);
     671                 :          0 :                     vstr_init(&vstr, len + sizeof(".__main__"));
     672                 :          0 :                     vstr_add_strn(&vstr, argv[a + 1], len);
     673                 :          0 :                     vstr_add_strn(&vstr, ".__main__", sizeof(".__main__") - 1);
     674                 :          0 :                     import_args[0] = mp_obj_new_str_from_vstr(&vstr);
     675                 :          0 :                     goto reimport;
     676                 :            :                 }
     677                 :            : 
     678                 :       1293 :                 ret = 0;
     679                 :       1293 :                 break;
     680         [ +  + ]:       3106 :             } else if (strcmp(argv[a], "-X") == 0) {
     681                 :       3082 :                 a += 1;
     682                 :            :             #if MICROPY_DEBUG_PRINTERS
     683         [ +  + ]:         24 :             } else if (strcmp(argv[a], "-v") == 0) {
     684                 :         22 :                 mp_verbose_flag++;
     685                 :            :             #endif
     686         [ +  - ]:          2 :             } else if (strncmp(argv[a], "-O", 2) == 0) {
     687         [ -  + ]:          2 :                 if (unichar_isdigit(argv[a][2])) {
     688                 :          0 :                     MP_STATE_VM(mp_optimise_value) = argv[a][2] & 0xf;
     689                 :            :                 } else {
     690                 :          2 :                     MP_STATE_VM(mp_optimise_value) = 0;
     691         [ +  + ]:          4 :                     for (char *p = argv[a] + 1; *p && *p == 'O'; p++, MP_STATE_VM(mp_optimise_value)++) {;
     692                 :            :                     }
     693                 :            :                 }
     694                 :            :             } else {
     695                 :          0 :                 return invalid_args();
     696                 :            :             }
     697                 :            :         } else {
     698                 :       1882 :             char *pathbuf = malloc(PATH_MAX);
     699                 :       1882 :             char *basedir = realpath(argv[a], pathbuf);
     700         [ -  + ]:       1882 :             if (basedir == NULL) {
     701                 :          0 :                 mp_printf(&mp_stderr_print, "%s: can't open file '%s': [Errno %d] %s\n", argv[0], argv[a], errno, strerror(errno));
     702                 :            :                 // CPython exits with 2 in such case
     703                 :          0 :                 ret = 2;
     704                 :          0 :                 break;
     705                 :            :             }
     706                 :            : 
     707                 :            :             // Set base dir of the script as first entry in sys.path.
     708                 :       1882 :             char *p = strrchr(basedir, '/');
     709                 :       1882 :             path_items[0] = mp_obj_new_str_via_qstr(basedir, p - basedir);
     710                 :       1882 :             free(pathbuf);
     711                 :            : 
     712                 :       1882 :             set_sys_argv(argv, argc, a);
     713                 :       1882 :             ret = do_file(argv[a]);
     714                 :       1882 :             break;
     715                 :            :         }
     716                 :            :     }
     717                 :            : 
     718                 :       3202 :     const char *inspect_env = getenv("MICROPYINSPECT");
     719   [ +  +  +  - ]:       3202 :     if (inspect_env && inspect_env[0] != '\0') {
     720                 :          2 :         inspect = true;
     721                 :            :     }
     722         [ +  + ]:       3202 :     if (ret == NOTHING_EXECUTED || inspect) {
     723   [ +  +  -  + ]:         29 :         if (isatty(0) || inspect) {
     724                 :         28 :             prompt_read_history();
     725                 :         28 :             ret = do_repl();
     726                 :         28 :             prompt_write_history();
     727                 :            :         } else {
     728                 :          1 :             ret = execute_from_lexer(LEX_SRC_STDIN, NULL, MP_PARSE_FILE_INPUT, false);
     729                 :            :         }
     730                 :            :     }
     731                 :            : 
     732                 :            :     #if MICROPY_PY_SYS_SETTRACE
     733                 :            :     MP_STATE_THREAD(prof_trace_callback) = MP_OBJ_NULL;
     734                 :            :     #endif
     735                 :            : 
     736                 :            :     #if MICROPY_PY_SYS_ATEXIT
     737                 :            :     // Beware, the sys.settrace callback should be disabled before running sys.atexit.
     738         [ +  + ]:       3202 :     if (mp_obj_is_callable(MP_STATE_VM(sys_exitfunc))) {
     739                 :          2 :         mp_call_function_0(MP_STATE_VM(sys_exitfunc));
     740                 :            :     }
     741                 :            :     #endif
     742                 :            : 
     743                 :            :     #if MICROPY_PY_MICROPYTHON_MEM_INFO
     744         [ +  + ]:       3202 :     if (mp_verbose_flag) {
     745                 :         10 :         mp_micropython_mem_info(0, NULL);
     746                 :            :     }
     747                 :            :     #endif
     748                 :            : 
     749                 :            :     #if MICROPY_PY_BLUETOOTH
     750                 :            :     void mp_bluetooth_deinit(void);
     751                 :            :     mp_bluetooth_deinit();
     752                 :            :     #endif
     753                 :            : 
     754                 :            :     #if MICROPY_PY_THREAD
     755                 :       3202 :     mp_thread_deinit();
     756                 :            :     #endif
     757                 :            : 
     758                 :            :     #if defined(MICROPY_UNIX_COVERAGE)
     759                 :       3202 :     gc_sweep_all();
     760                 :            :     #endif
     761                 :            : 
     762                 :       3202 :     mp_deinit();
     763                 :            : 
     764                 :            :     #if MICROPY_ENABLE_GC && !defined(NDEBUG)
     765                 :            :     // We don't really need to free memory since we are about to exit the
     766                 :            :     // process, but doing so helps to find memory leaks.
     767                 :            :     #if !MICROPY_GC_SPLIT_HEAP
     768                 :            :     free(heap);
     769                 :            :     #else
     770         [ +  + ]:      16010 :     for (size_t i = 0; i < MICROPY_GC_SPLIT_HEAP_N_HEAPS; i++) {
     771                 :      12808 :         free(heaps[i]);
     772                 :            :     }
     773                 :            :     #endif
     774                 :            :     #endif
     775                 :            : 
     776                 :            :     // printf("total bytes = %d\n", m_get_total_bytes_allocated());
     777                 :       3202 :     return ret & 0xff;
     778                 :            : }
     779                 :            : 
     780                 :          0 : void nlr_jump_fail(void *val) {
     781                 :            :     #if MICROPY_USE_READLINE == 1
     782                 :          0 :     mp_hal_stdio_mode_orig();
     783                 :            :     #endif
     784                 :          0 :     fprintf(stderr, "FATAL: uncaught NLR %p\n", val);
     785                 :          0 :     exit(1);
     786                 :            : }

Generated by: LCOV version 1.15-5-g462f71d