Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
2 : : // SPDX-FileCopyrightText: 2018 Philip Chimento <philip.chimento@gmail.com>
3 : : // SPDX-FileContributor: Philip Chimento <philip.chimento@gmail.com>
4 : :
5 : : #include <config.h> // for HAVE_READLINE_READLINE_H, HAVE_UNISTD_H
6 : :
7 : : #include <stdint.h>
8 : : #include <stdio.h> // for feof, fflush, fgets, stdin, stdout
9 : :
10 : : #ifdef HAVE_READLINE_READLINE_H
11 : : # include <readline/history.h>
12 : : # include <readline/readline.h>
13 : : #endif
14 : :
15 : : #include <glib.h>
16 : :
17 : : #include <js/CallArgs.h>
18 : : #include <js/ErrorReport.h> // for ReportUncatchableException
19 : : #include <js/PropertyAndElement.h>
20 : : #include <js/PropertySpec.h>
21 : : #include <js/Realm.h>
22 : : #include <js/RootingAPI.h>
23 : : #include <js/String.h>
24 : : #include <js/TypeDecls.h>
25 : : #include <js/Utility.h> // for UniqueChars
26 : : #include <js/Value.h>
27 : : #include <jsapi.h> // for JS_WrapObject
28 : :
29 : : #include "gjs/atoms.h"
30 : : #include "gjs/auto.h"
31 : : #include "gjs/context-private.h"
32 : : #include "gjs/context.h"
33 : : #include "gjs/global.h"
34 : : #include "gjs/jsapi-util-args.h"
35 : : #include "gjs/jsapi-util.h"
36 : : #include "gjs/macros.h"
37 : : #include "gjs/module.h"
38 : :
39 : : #include "util/console.h"
40 : :
41 : : GJS_JSAPI_RETURN_CONVENTION
42 : 10 : static bool quit(JSContext* cx, unsigned argc, JS::Value* vp) {
43 : 10 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
44 : :
45 : : int32_t exitcode;
46 [ - + ]: 10 : if (!gjs_parse_call_args(cx, "quit", args, "i", "exitcode", &exitcode))
47 : 0 : return false;
48 : :
49 : 10 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
50 : 10 : gjs->exit(exitcode);
51 : 10 : JS::ReportUncatchableException(cx);
52 : 10 : return false;
53 : : }
54 : :
55 : : GJS_JSAPI_RETURN_CONVENTION
56 : 278 : static bool do_readline(JSContext* cx, unsigned argc, JS::Value* vp) {
57 : 278 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
58 : :
59 : 278 : JS::UniqueChars prompt;
60 [ - + ]: 278 : if (!gjs_parse_call_args(cx, "readline", args, "|s", "prompt", &prompt))
61 : 0 : return false;
62 : :
63 : 278 : Gjs::AutoChar line;
64 : : do {
65 [ - + ]: 278 : const char* real_prompt = prompt ? prompt.get() : "db> ";
66 : : #ifdef HAVE_READLINE_READLINE_H
67 [ - + ]: 278 : if (gjs_console_is_tty(stdin_fd)) {
68 : 0 : line = readline(real_prompt);
69 : : } else {
70 : : #else
71 : : {
72 : : #endif // HAVE_READLINE_READLINE_H
73 : : char buf[256];
74 : 278 : g_print("%s", real_prompt);
75 : 278 : fflush(stdout);
76 [ + + ]: 278 : if (!fgets(buf, sizeof buf, stdin))
77 : 5 : buf[0] = '\0';
78 : 556 : line.reset(g_strdup(g_strchomp(buf)));
79 : :
80 [ + - ]: 278 : if (!gjs_console_is_tty(stdin_fd)) {
81 [ + + ]: 278 : if (feof(stdin)) {
82 : 5 : g_print("[quit due to end of input]\n");
83 : 5 : line.reset(g_strdup("quit"));
84 : : } else {
85 : 273 : g_print("%s\n", line.get());
86 : : }
87 : : }
88 : : }
89 : :
90 : : // EOF, return null
91 [ - + ]: 278 : if (!line) {
92 : 0 : args.rval().setNull();
93 : 0 : return true;
94 : : }
95 [ + - - + : 278 : } while (line && line.get()[0] == '\0');
- + ]
96 : :
97 : : /* Add line to history and convert it to a JSString so that we can pass it
98 : : * back as the return value */
99 : : #ifdef HAVE_READLINE_READLINE_H
100 : 278 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
101 : 278 : add_history(line);
102 : 278 : gjs_console_write_repl_history(gjs->repl_history_path());
103 : : #endif
104 : 278 : args.rval().setString(JS_NewStringCopyZ(cx, line));
105 : 278 : return true;
106 : 278 : }
107 : :
108 : 143 : static bool get_source_map_registry(JSContext* cx, unsigned argc,
109 : : JS::Value* vp) {
110 : 143 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
111 : 143 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
112 : :
113 : 143 : JS::RootedObject registry{cx, gjs_get_source_map_registry(gjs->global())};
114 [ - + ]: 143 : if (!JS_WrapObject(cx, ®istry)) {
115 : 0 : gjs_log_exception(cx);
116 : 0 : return false;
117 : : }
118 : 143 : args.rval().setObject(*registry);
119 : 143 : return true;
120 : 143 : }
121 : :
122 : : // clang-format off
123 : : static JSFunctionSpec debugger_funcs[] = {
124 : : JS_FN("quit", quit, 1, GJS_MODULE_PROP_FLAGS),
125 : : JS_FN("readline", do_readline, 1, GJS_MODULE_PROP_FLAGS),
126 : : JS_FN("getSourceMapRegistry", get_source_map_registry, 0, GJS_MODULE_PROP_FLAGS),
127 : : JS_FS_END
128 : : };
129 : : // clang-format on
130 : :
131 : 25 : void gjs_context_setup_debugger_console(GjsContext* self) {
132 : 25 : auto* gjs = GjsContextPrivate::from_object(self);
133 : 25 : JSContext* cx = gjs->context();
134 : :
135 : : JS::RootedObject debugger_global(
136 : 25 : cx, gjs_create_global_object(cx, GjsGlobalType::DEBUGGER));
137 : :
138 : : // Enter realm of the debugger and initialize it with the debuggee
139 : 25 : JSAutoRealm ar(cx, debugger_global);
140 : 25 : JS::RootedObject debuggee{cx, gjs->global()};
141 [ - + ]: 25 : if (!JS_WrapObject(cx, &debuggee)) {
142 : 0 : gjs_log_exception(cx);
143 : 0 : return;
144 : : }
145 : :
146 : 25 : JS::RootedValue v_debuggee(cx, JS::ObjectValue(*debuggee));
147 : 25 : if (!JS_SetPropertyById(cx, debugger_global, gjs->atoms().debuggee(),
148 : 25 : v_debuggee) ||
149 [ + - + - ]: 50 : !JS_DefineFunctions(cx, debugger_global, debugger_funcs) ||
150 [ - + - + ]: 50 : !gjs_define_global_properties(cx, debugger_global,
151 : : GjsGlobalType::DEBUGGER, "GJS debugger",
152 : : "debugger"))
153 : 0 : gjs_log_exception(cx);
154 [ + - + - : 25 : }
+ - ]
|