LCOV - code coverage report
Current view: top level - gjs - console.cpp (source / functions) Coverage Total Hit
Test: gjs- Code Coverage Lines: 79.0 % 200 158
Test Date: 2025-05-21 00:02:11 Functions: 100.0 % 6 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 69.2 % 120 83

             Branch data     Line data    Source code
       1                 :             : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
       2                 :             : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
       3                 :             : // SPDX-FileCopyrightText: 2008 litl, LLC
       4                 :             : 
       5                 :             : #include <config.h>  // for PACKAGE_STRING
       6                 :             : 
       7                 :             : #include <locale.h>  // for setlocale, LC_ALL
       8                 :             : #include <stdint.h>
       9                 :             : #include <stdlib.h>  // for EXIT_SUCCESS / EXIT_FAILURE
      10                 :             : #include <string.h>  // for strcmp, strlen
      11                 :             : 
      12                 :             : #ifdef HAVE_UNISTD_H
      13                 :             : #    include <unistd.h>  // for close
      14                 :             : #elif defined (_WIN32)
      15                 :             : #    include <io.h>
      16                 :             : #endif
      17                 :             : 
      18                 :             : #include <gio/gio.h>
      19                 :             : #include <glib-object.h>
      20                 :             : #include <glib.h>
      21                 :             : 
      22                 :             : #include "gjs/auto.h"
      23                 :             : #include "gjs/gerror-result.h"
      24                 :             : #include "gjs/gjs.h"
      25                 :             : #include "util/console.h"
      26                 :             : 
      27                 :             : static Gjs::AutoStrv include_path;
      28                 :             : static Gjs::AutoStrv coverage_prefixes;
      29                 :             : static Gjs::AutoChar coverage_output_path;
      30                 :             : static Gjs::AutoChar profile_output_path;
      31                 :             : static Gjs::AutoChar command;
      32                 :             : static gboolean print_version = false;
      33                 :             : static gboolean print_js_version = false;
      34                 :             : static gboolean debugging = false;
      35                 :             : static gboolean exec_as_module = false;
      36                 :             : static bool enable_profiler = false;
      37                 :             : 
      38                 :             : static gboolean parse_profile_arg(const char *, const char *, void *, GError **);
      39                 :             : 
      40                 :             : using GjsAutoGOptionContext =
      41                 :         128 :     Gjs::AutoPointer<GOptionContext, GOptionContext, g_option_context_free>;
      42                 :             : 
      43                 :             : // clang-format off
      44                 :             : static GOptionEntry entries[] = {
      45                 :             :     { "version", 0, 0, G_OPTION_ARG_NONE, &print_version, "Print GJS version and exit" },
      46                 :             :     { "jsversion", 0, 0, G_OPTION_ARG_NONE, &print_js_version,
      47                 :             :         "Print version of the JS engine and exit" },
      48                 :             :     { "command", 'c', 0, G_OPTION_ARG_STRING, command.out(), "Program passed in as a string", "COMMAND" },
      49                 :             :     { "coverage-prefix", 'C', 0, G_OPTION_ARG_STRING_ARRAY, coverage_prefixes.out(),
      50                 :             :       "Add the prefix PREFIX to the list of files to generate coverage info for", "PREFIX" },
      51                 :             :     { "coverage-output", 0, 0, G_OPTION_ARG_STRING, coverage_output_path.out(),
      52                 :             :       "Write coverage output to a directory DIR. This option is mandatory when using --coverage-prefix", "DIR", },
      53                 :             :     { "include-path", 'I', 0, G_OPTION_ARG_STRING_ARRAY, include_path.out(),
      54                 :             :         "Add DIR to the list of paths to search for JS files", "DIR" },
      55                 :             :     { "module", 'm', 0, G_OPTION_ARG_NONE, &exec_as_module,
      56                 :             :         "Execute the file as a module" },
      57                 :             :     { "profile", 0, G_OPTION_FLAG_OPTIONAL_ARG | G_OPTION_FLAG_FILENAME,
      58                 :             :         G_OPTION_ARG_CALLBACK, reinterpret_cast<void *>(&parse_profile_arg),
      59                 :             :         "Enable the profiler and write output to FILE (default: gjs-$PID.syscap)",
      60                 :             :         "FILE" },
      61                 :             :     { "debugger", 'd', 0, G_OPTION_ARG_NONE, &debugging, "Start in debug mode" },
      62                 :             :     { NULL }
      63                 :             : };
      64                 :             : // clang-format on
      65                 :             : 
      66                 :          76 : [[nodiscard]] static Gjs::AutoStrv strndupv(int n, char* const* strv) {
      67                 :             : #if GLIB_CHECK_VERSION(2, 68, 0)
      68                 :          76 :     Gjs::AutoPointer<GStrvBuilder, GStrvBuilder, g_strv_builder_unref> builder{
      69                 :          76 :         g_strv_builder_new()};
      70                 :             : 
      71         [ +  + ]:         292 :     for (int i = 0; i < n; ++i)
      72                 :         216 :         g_strv_builder_add(builder, strv[i]);
      73                 :             : 
      74                 :          76 :     return g_strv_builder_end(builder);
      75                 :             : 
      76                 :             : #else
      77                 :             : 
      78                 :             :     int ix;
      79                 :             :     if (n == 0)
      80                 :             :         return NULL;
      81                 :             :     char **retval = g_new(char *, n + 1);
      82                 :             :     for (ix = 0; ix < n; ix++)
      83                 :             :         retval[ix] = g_strdup(strv[ix]);
      84                 :             :     retval[n] = NULL;
      85                 :             :     return retval;
      86                 :             : #endif  // GLIB_CHECK_VERSION(2, 68, 0)
      87                 :          76 : }
      88                 :             : 
      89                 :           3 : [[nodiscard]] static Gjs::AutoStrv strcatv(char** strv1, char** strv2) {
      90   [ +  -  -  + ]:           3 :     if (strv1 == NULL && strv2 == NULL)
      91                 :           0 :         return NULL;
      92         [ +  - ]:           3 :     if (strv1 == NULL)
      93                 :           3 :         return g_strdupv(strv2);
      94         [ #  # ]:           0 :     if (strv2 == NULL)
      95                 :           0 :         return g_strdupv(strv1);
      96                 :             : 
      97                 :             : #if GLIB_CHECK_VERSION(2, 70, 0)
      98                 :             :     Gjs::AutoPointer<GStrvBuilder, GStrvBuilder, g_strv_builder_unref> builder{
      99                 :           0 :         g_strv_builder_new()};
     100                 :             : 
     101                 :           0 :     g_strv_builder_addv(builder, const_cast<const char**>(strv1));
     102                 :           0 :     g_strv_builder_addv(builder, const_cast<const char**>(strv2));
     103                 :             : 
     104                 :           0 :     return g_strv_builder_end(builder);
     105                 :             : 
     106                 :             : #else
     107                 :             : 
     108                 :             :     unsigned len1 = g_strv_length(strv1);
     109                 :             :     unsigned len2 = g_strv_length(strv2);
     110                 :             :     char **retval = g_new(char *, len1 + len2 + 1);
     111                 :             :     unsigned ix;
     112                 :             : 
     113                 :             :     for (ix = 0; ix < len1; ix++)
     114                 :             :         retval[ix] = g_strdup(strv1[ix]);
     115                 :             :     for (ix = 0; ix < len2; ix++)
     116                 :             :         retval[len1 + ix] = g_strdup(strv2[ix]);
     117                 :             :     retval[len1 + len2] = NULL;
     118                 :             : 
     119                 :             :     return retval;
     120                 :             : #endif  // GLIB_CHECK_VERSION(2, 70, 0)
     121                 :           0 : }
     122                 :             : 
     123                 :           6 : static gboolean parse_profile_arg(const char* option_name [[maybe_unused]],
     124                 :             :                                   const char* value, void*, GError**) {
     125                 :           6 :     enable_profiler = true;
     126                 :           6 :     profile_output_path = Gjs::AutoChar{value, Gjs::TakeOwnership{}};
     127                 :           6 :     return true;
     128                 :             : }
     129                 :             : 
     130                 :             : static void
     131                 :          62 : check_script_args_for_stray_gjs_args(int           argc,
     132                 :             :                                      char * const *argv)
     133                 :             : {
     134                 :          62 :     Gjs::AutoError error;
     135                 :          62 :     Gjs::AutoStrv new_coverage_prefixes;
     136                 :          62 :     Gjs::AutoChar new_coverage_output_path;
     137                 :          62 :     Gjs::AutoStrv new_include_paths;
     138                 :             :     // Don't add new entries here. This is only for arguments that were
     139                 :             :     // previously accepted after the script name on the command line, for
     140                 :             :     // backwards compatibility.
     141                 :             :     // clang-format off
     142                 :          62 :     GOptionEntry script_check_entries[] = {
     143                 :          62 :         { "coverage-prefix", 'C', 0, G_OPTION_ARG_STRING_ARRAY, new_coverage_prefixes.out() },
     144                 :          62 :         { "coverage-output", 0, 0, G_OPTION_ARG_STRING, new_coverage_output_path.out() },
     145                 :          62 :         { "include-path", 'I', 0, G_OPTION_ARG_STRING_ARRAY, new_include_paths.out() },
     146                 :             :         { NULL }
     147                 :          62 :     };
     148                 :             :     // clang-format on
     149                 :             : 
     150                 :          62 :     Gjs::AutoStrv argv_copy{g_new(char*, argc + 2)};
     151                 :             :     int ix;
     152                 :             : 
     153                 :          62 :     argv_copy[0] = g_strdup("dummy"); /* Fake argv[0] for GOptionContext */
     154         [ +  + ]:          79 :     for (ix = 0; ix < argc; ix++)
     155                 :          34 :         argv_copy[ix + 1] = g_strdup(argv[ix]);
     156                 :          62 :     argv_copy[argc + 1] = NULL;
     157                 :             : 
     158                 :          62 :     GjsAutoGOptionContext script_options = g_option_context_new(NULL);
     159                 :          62 :     g_option_context_set_ignore_unknown_options(script_options, true);
     160                 :          62 :     g_option_context_set_help_enabled(script_options, false);
     161                 :          62 :     g_option_context_add_main_entries(script_options, script_check_entries, NULL);
     162         [ -  + ]:          62 :     if (!g_option_context_parse_strv(script_options, argv_copy.out(), &error)) {
     163                 :           0 :         g_warning("Scanning script arguments failed: %s", error->message);
     164                 :           0 :         return;
     165                 :             :     }
     166                 :             : 
     167         [ +  + ]:          62 :     if (new_coverage_prefixes) {
     168                 :           2 :         g_warning("You used the --coverage-prefix option after the script on "
     169                 :             :                   "the GJS command line. Support for this will be removed in a "
     170                 :             :                   "future version. Place the option before the script or use "
     171                 :             :                   "the GJS_COVERAGE_PREFIXES environment variable.");
     172                 :           2 :         coverage_prefixes = strcatv(coverage_prefixes, new_coverage_prefixes);
     173                 :             :     }
     174         [ +  + ]:          62 :     if (new_include_paths) {
     175                 :           1 :         g_warning("You used the --include-path option after the script on the "
     176                 :             :                   "GJS command line. Support for this will be removed in a "
     177                 :             :                   "future version. Place the option before the script or use "
     178                 :             :                   "the GJS_PATH environment variable.");
     179                 :           1 :         include_path = strcatv(include_path, new_include_paths);
     180                 :             :     }
     181         [ +  + ]:          62 :     if (new_coverage_output_path) {
     182                 :           2 :         g_warning(
     183                 :             :             "You used the --coverage-output option after the script on "
     184                 :             :             "the GJS command line. Support for this will be removed in a "
     185                 :             :             "future version. Place the option before the script or use "
     186                 :             :             "the GJS_COVERAGE_OUTPUT environment variable.");
     187                 :           2 :         coverage_output_path = new_coverage_output_path;
     188                 :             :     }
     189   [ +  -  +  -  :          62 : }
          +  -  +  -  +  
                -  +  - ]
     190                 :             : 
     191                 :          62 : int define_argv_and_eval_script(GjsContext* js_context, int argc,
     192                 :             :                                 char* const* argv, const char* script,
     193                 :             :                                 size_t len, const char* filename) {
     194                 :          62 :     gjs_context_set_argv(js_context, argc, const_cast<const char**>(argv));
     195                 :             : 
     196                 :          62 :     Gjs::AutoError error;
     197                 :             :     /* evaluate the script */
     198                 :          62 :     int code = 0;
     199         [ +  + ]:          62 :     if (exec_as_module) {
     200                 :           5 :         Gjs::AutoUnref<GFile> output{g_file_new_for_commandline_arg(filename)};
     201                 :           5 :         Gjs::AutoChar uri{g_file_get_uri(output)};
     202         [ -  + ]:           5 :         if (!gjs_context_register_module(js_context, uri, uri, &error)) {
     203                 :           0 :             g_critical("%s", error->message);
     204                 :           0 :             code = 1;
     205                 :             :         }
     206                 :             : 
     207                 :           5 :         uint8_t code_u8 = 0;
     208   [ +  -  +  - ]:           9 :         if (!code &&
     209         [ +  - ]:           5 :             !gjs_context_eval_module(js_context, uri, &code_u8, &error)) {
     210                 :           4 :             code = code_u8;
     211                 :             : 
     212         [ -  + ]:           4 :             if (!g_error_matches(error, GJS_ERROR, GJS_ERROR_SYSTEM_EXIT))
     213                 :           0 :                 g_critical("%s", error->message);
     214                 :             :         }
     215         [ +  + ]:          61 :     } else if (!gjs_context_eval(js_context, script, len, filename, &code,
     216                 :             :                                  &error)) {
     217         [ -  + ]:          23 :         if (!g_error_matches(error, GJS_ERROR, GJS_ERROR_SYSTEM_EXIT))
     218                 :           0 :             g_critical("%s", error->message);
     219                 :             :     }
     220                 :         120 :     return code;
     221                 :          60 : }
     222                 :             : 
     223                 :          76 : int main(int argc, char** argv) {
     224                 :          76 :     Gjs::AutoError error;
     225                 :             :     const char *filename;
     226                 :             :     const char *program_name;
     227                 :             :     gsize len;
     228                 :          76 :     int gjs_argc = argc, script_argc, ix;
     229                 :             :     char * const *script_argv;
     230                 :             :     const char *env_coverage_output_path;
     231                 :          76 :     bool interactive_mode = false;
     232                 :             : 
     233                 :          76 :     setlocale(LC_ALL, "");
     234                 :             : 
     235                 :          76 :     GjsAutoGOptionContext context = g_option_context_new(NULL);
     236                 :          76 :     g_option_context_set_ignore_unknown_options(context, true);
     237                 :          76 :     g_option_context_set_help_enabled(context, false);
     238                 :             : 
     239                 :          76 :     Gjs::AutoStrv argv_copy_addr{g_strdupv(argv)};
     240                 :          76 :     char** argv_copy = argv_copy_addr;
     241                 :             : 
     242                 :          76 :     g_option_context_add_main_entries(context, entries, NULL);
     243         [ -  + ]:          76 :     if (!g_option_context_parse_strv(context, &argv_copy, &error))
     244                 :           0 :         g_error("option parsing failed: %s", error->message);
     245                 :             : 
     246                 :             :     /* Split options so we pass unknown ones through to the JS script */
     247                 :          76 :     int argc_copy = g_strv_length(argv_copy);
     248         [ +  + ]:         123 :     for (ix = 1; ix < argc; ix++) {
     249                 :             :         /* Check if a file was given and split after it */
     250   [ +  +  +  + ]:         119 :         if (argc_copy >= 2 && strcmp(argv[ix], argv_copy[1]) == 0) {
     251                 :             :             /* Filename given; split after this argument */
     252                 :          51 :             gjs_argc = ix + 1;
     253                 :          51 :             break;
     254                 :             :         }
     255                 :             : 
     256                 :             :         /* Check if -c or --command was given and split after following arg */
     257   [ +  +  +  +  :          71 :         if (command && (strcmp(argv[ix], "-c") == 0 ||
                   +  + ]
     258         [ -  + ]:          71 :                         strcmp(argv[ix], "--command") == 0)) {
     259                 :          21 :             gjs_argc = ix + 2;
     260                 :          21 :             break;
     261                 :             :         }
     262                 :             :     }
     263                 :          76 :     Gjs::AutoStrv gjs_argv_addr{strndupv(gjs_argc, argv)};
     264                 :          76 :     char** gjs_argv = gjs_argv_addr;
     265                 :          76 :     script_argc = argc - gjs_argc;
     266                 :          76 :     script_argv = argv + gjs_argc;
     267                 :             : 
     268                 :             :     /* Parse again, only the GJS options this time */
     269                 :          76 :     include_path.release();
     270                 :          76 :     coverage_prefixes.release();
     271                 :          76 :     coverage_output_path.release();
     272                 :          76 :     command.release();
     273                 :          76 :     print_version = false;
     274                 :          76 :     print_js_version = false;
     275                 :          76 :     debugging = false;
     276                 :          76 :     exec_as_module = false;
     277                 :          76 :     g_option_context_set_ignore_unknown_options(context, false);
     278                 :          76 :     g_option_context_set_help_enabled(context, true);
     279         [ +  + ]:          76 :     if (!g_option_context_parse_strv(context, &gjs_argv, &error)) {
     280                 :             :         Gjs::AutoChar help_text{
     281                 :           2 :             g_option_context_get_help(context, true, nullptr)};
     282                 :           2 :         g_printerr("%s\n\n%s\n", error->message, help_text.get());
     283                 :           2 :         return EXIT_FAILURE;
     284                 :           2 :     }
     285                 :             : 
     286         [ +  + ]:          66 :     if (print_version) {
     287                 :           2 :         g_print("%s\n", PACKAGE_STRING);
     288                 :           2 :         return EXIT_SUCCESS;
     289                 :             :     }
     290                 :             : 
     291         [ +  + ]:          64 :     if (print_js_version) {
     292                 :           2 :         g_print("%s\n", gjs_get_js_version());
     293                 :           2 :         return EXIT_SUCCESS;
     294                 :             :     }
     295                 :             : 
     296                 :          62 :     Gjs::AutoChar program_path;
     297                 :          62 :     gjs_argc = g_strv_length(gjs_argv);
     298                 :          62 :     Gjs::AutoChar script;
     299         [ +  + ]:          62 :     if (command) {
     300                 :          21 :         script = command;
     301                 :          21 :         len = strlen(script);
     302                 :          21 :         filename = "<command line>";
     303                 :          21 :         program_name = gjs_argv[0];
     304         [ -  + ]:          41 :     } else if (gjs_argc == 1) {
     305         [ #  # ]:           0 :         if (exec_as_module) {
     306                 :           0 :             g_warning(
     307                 :             :                 "'-m' requires a file argument.\nExample: gjs -m main.js");
     308                 :           0 :             return EXIT_FAILURE;
     309                 :             :         }
     310                 :             : 
     311                 :           0 :         script = g_strdup("const Console = imports.console; Console.interact();");
     312                 :           0 :         len = strlen(script);
     313                 :           0 :         filename = "<stdin>";
     314                 :           0 :         program_name = gjs_argv[0];
     315                 :           0 :         interactive_mode = true;
     316                 :             :     } else {
     317                 :             :         /* All unprocessed options should be in script_argv */
     318                 :          41 :         g_assert(gjs_argc == 2);
     319                 :             :         Gjs::AutoUnref<GFile> input{
     320                 :          41 :             g_file_new_for_commandline_arg(gjs_argv[1])};
     321         [ -  + ]:          41 :         if (!g_file_load_contents(input, nullptr, script.out(), &len, nullptr,
     322                 :             :                                   &error)) {
     323                 :           0 :             g_printerr("%s\n", error->message);
     324                 :           0 :             return EXIT_FAILURE;
     325                 :             :         }
     326                 :          41 :         program_path = g_file_get_path(input);
     327                 :          41 :         filename = gjs_argv[1];
     328                 :          41 :         program_name = gjs_argv[1];
     329         [ +  - ]:          41 :     }
     330                 :             : 
     331                 :             :     /* This should be removed after a suitable time has passed */
     332                 :          62 :     check_script_args_for_stray_gjs_args(script_argc, script_argv);
     333                 :             : 
     334                 :             :     /* Check for GJS_TRACE_FD for sysprof profiling */
     335                 :          62 :     const char* env_tracefd = g_getenv("GJS_TRACE_FD");
     336                 :          62 :     int tracefd = -1;
     337         [ -  + ]:          62 :     if (env_tracefd) {
     338                 :           0 :         tracefd = g_ascii_strtoll(env_tracefd, nullptr, 10);
     339                 :           0 :         g_setenv("GJS_TRACE_FD", "", true);
     340         [ #  # ]:           0 :         if (tracefd > 0)
     341                 :           0 :             enable_profiler = true;
     342                 :             :     }
     343                 :             : 
     344   [ -  +  -  - ]:          62 :     if (interactive_mode && enable_profiler) {
     345                 :           0 :         g_message("Profiler disabled in interactive mode.");
     346                 :           0 :         enable_profiler = false;
     347                 :           0 :         g_unsetenv("GJS_ENABLE_PROFILER");  /* ignore env var in eval() */
     348                 :           0 :         g_unsetenv("GJS_TRACE_FD");         /* ignore env var in eval() */
     349                 :             :     }
     350                 :             : 
     351                 :          62 :     const char* env_coverage_prefixes = g_getenv("GJS_COVERAGE_PREFIXES");
     352         [ -  + ]:          62 :     if (env_coverage_prefixes)
     353                 :           0 :         coverage_prefixes = g_strsplit(env_coverage_prefixes, ":", -1);
     354                 :             : 
     355         [ +  + ]:          62 :     if (coverage_prefixes)
     356                 :           3 :         gjs_coverage_enable();
     357                 :             : 
     358                 :             : #ifdef HAVE_READLINE_READLINE_H
     359                 :          62 :     Gjs::AutoChar repl_history_path = gjs_console_get_repl_history_path();
     360                 :             : #else
     361                 :             :     Gjs::AutoChar repl_history_path = nullptr;
     362                 :             : #endif
     363                 :             : 
     364                 :             :     Gjs::AutoUnref<GjsContext> js_context{GJS_CONTEXT(g_object_new(
     365                 :             :         GJS_TYPE_CONTEXT,
     366                 :             :         // clang-format off
     367                 :             :         "search-path", include_path.get(),
     368                 :             :         "program-name", program_name,
     369                 :             :         "program-path", program_path.get(),
     370                 :             :         "profiler-enabled", enable_profiler,
     371                 :             :         "exec-as-module", exec_as_module,
     372                 :             :         "repl-history-path", repl_history_path.get(),
     373                 :             :         // clang-format on
     374                 :          62 :         nullptr))};
     375                 :             : 
     376                 :          62 :     env_coverage_output_path = g_getenv("GJS_COVERAGE_OUTPUT");
     377         [ -  + ]:          62 :     if (env_coverage_output_path != NULL) {
     378                 :           0 :         g_free(coverage_output_path);
     379                 :           0 :         coverage_output_path = g_strdup(env_coverage_output_path);
     380                 :             :     }
     381                 :             : 
     382                 :          62 :     Gjs::AutoUnref<GjsCoverage> coverage;
     383         [ +  + ]:          62 :     if (coverage_prefixes) {
     384         [ -  + ]:           3 :         if (!coverage_output_path)
     385                 :           0 :             g_error("--coverage-output is required when taking coverage statistics");
     386                 :             : 
     387                 :             :         Gjs::AutoUnref<GFile> output{
     388                 :           3 :             g_file_new_for_commandline_arg(coverage_output_path)};
     389                 :           3 :         coverage = gjs_coverage_new(coverage_prefixes, js_context, output);
     390                 :           3 :     }
     391                 :             : 
     392   [ +  +  +  +  :          62 :     if (enable_profiler && profile_output_path) {
                   +  + ]
     393                 :           1 :         GjsProfiler *profiler = gjs_context_get_profiler(js_context);
     394                 :           1 :         gjs_profiler_set_filename(profiler, profile_output_path);
     395   [ +  +  -  + ]:          61 :     } else if (enable_profiler && tracefd > -1) {
     396                 :           0 :         GjsProfiler* profiler = gjs_context_get_profiler(js_context);
     397                 :           0 :         gjs_profiler_set_fd(profiler, tracefd);
     398                 :           0 :         tracefd = -1;
     399                 :             :     }
     400                 :             : 
     401         [ -  + ]:          62 :     if (tracefd != -1) {
     402                 :           0 :         close(tracefd);
     403                 :           0 :         tracefd = -1;
     404                 :             :     }
     405                 :             : 
     406                 :             :     /* If we're debugging, set up the debugger. It will break on the first
     407                 :             :      * frame. */
     408         [ +  + ]:          62 :     if (debugging)
     409                 :          25 :         gjs_context_setup_debugger_console(js_context);
     410                 :             : 
     411                 :          62 :     int code = define_argv_and_eval_script(js_context, script_argc, script_argv,
     412                 :             :                                            script, len, filename);
     413                 :             : 
     414                 :             :     /* Probably doesn't make sense to write statistics on failure */
     415   [ +  +  +  -  :          60 :     if (coverage && code == 0)
                   +  + ]
     416                 :           3 :         gjs_coverage_write_statistics(coverage);
     417                 :             : 
     418         [ +  + ]:          60 :     if (debugging)
     419                 :          25 :         g_print("Program exited with code %d\n", code);
     420                 :             : 
     421                 :          60 :     return code;
     422                 :          66 : }
        

Generated by: LCOV version 2.0-1