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/PropertyAndElement.h>
19 : : #include <js/PropertySpec.h>
20 : : #include <js/Realm.h>
21 : : #include <js/RootingAPI.h>
22 : : #include <js/String.h>
23 : : #include <js/TypeDecls.h>
24 : : #include <js/Utility.h> // for UniqueChars
25 : : #include <js/Value.h>
26 : : #include <jsapi.h> // for JS_WrapObject
27 : :
28 : : #include "gjs/atoms.h"
29 : : #include "gjs/context-private.h"
30 : : #include "gjs/context.h"
31 : : #include "gjs/global.h"
32 : : #include "gjs/jsapi-util-args.h"
33 : : #include "gjs/jsapi-util.h"
34 : : #include "gjs/macros.h"
35 : :
36 : : #include "util/console.h"
37 : :
38 : : GJS_JSAPI_RETURN_CONVENTION
39 : 5 : static bool quit(JSContext* cx, unsigned argc, JS::Value* vp) {
40 : 5 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
41 : :
42 : : int32_t exitcode;
43 [ - + ]: 5 : if (!gjs_parse_call_args(cx, "quit", args, "i", "exitcode", &exitcode))
44 : 0 : return false;
45 : :
46 : 5 : GjsContextPrivate* gjs = GjsContextPrivate::from_cx(cx);
47 : 5 : gjs->exit(exitcode);
48 : 5 : return false; // without gjs_throw() == "throw uncatchable exception"
49 : : }
50 : :
51 : : GJS_JSAPI_RETURN_CONVENTION
52 : 219 : static bool do_readline(JSContext* cx, unsigned argc, JS::Value* vp) {
53 : 219 : JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
54 : :
55 : 219 : JS::UniqueChars prompt;
56 [ - + ]: 219 : if (!gjs_parse_call_args(cx, "readline", args, "|s", "prompt", &prompt))
57 : 0 : return false;
58 : :
59 : 219 : GjsAutoChar line;
60 : : do {
61 [ - + ]: 219 : const char* real_prompt = prompt ? prompt.get() : "db> ";
62 : : #ifdef HAVE_READLINE_READLINE_H
63 [ - + ]: 219 : if (gjs_console_is_tty(stdin_fd)) {
64 : 0 : line = readline(real_prompt);
65 : : } else {
66 : : #else
67 : : {
68 : : #endif // HAVE_READLINE_READLINE_H
69 : : char buf[256];
70 : 219 : g_print("%s", real_prompt);
71 : 219 : fflush(stdout);
72 [ - + ]: 219 : if (!fgets(buf, sizeof buf, stdin))
73 : 0 : buf[0] = '\0';
74 : 438 : line.reset(g_strdup(g_strchomp(buf)));
75 : :
76 [ + - ]: 219 : if (!gjs_console_is_tty(stdin_fd)) {
77 [ - + ]: 219 : if (feof(stdin)) {
78 : 0 : g_print("[quit due to end of input]\n");
79 : 0 : line.reset(g_strdup("quit"));
80 : : } else {
81 : 219 : g_print("%s\n", line.get());
82 : : }
83 : : }
84 : : }
85 : :
86 : : /* EOF, return null */
87 [ - + ]: 219 : if (!line) {
88 : 0 : args.rval().setNull();
89 : 0 : return true;
90 : : }
91 [ + - - + : 219 : } while (line && line.get()[0] == '\0');
- + ]
92 : :
93 : : /* Add line to history and convert it to a JSString so that we can pass it
94 : : * back as the return value */
95 : : #ifdef HAVE_READLINE_READLINE_H
96 : 219 : add_history(line);
97 : : #endif
98 : 219 : args.rval().setString(JS_NewStringCopyZ(cx, line));
99 : 219 : return true;
100 : 219 : }
101 : :
102 : : // clang-format off
103 : : static JSFunctionSpec debugger_funcs[] = {
104 : : JS_FN("quit", quit, 1, GJS_MODULE_PROP_FLAGS),
105 : : JS_FN("readline", do_readline, 1, GJS_MODULE_PROP_FLAGS),
106 : : JS_FS_END
107 : : };
108 : : // clang-format on
109 : :
110 : 20 : void gjs_context_setup_debugger_console(GjsContext* self) {
111 : 20 : auto* gjs = GjsContextPrivate::from_object(self);
112 : 20 : JSContext* cx = gjs->context();
113 : :
114 : : JS::RootedObject debugger_global(
115 : 20 : cx, gjs_create_global_object(cx, GjsGlobalType::DEBUGGER));
116 : :
117 : : // Enter realm of the debugger and initialize it with the debuggee
118 : 20 : JSAutoRealm ar(cx, debugger_global);
119 : 20 : JS::RootedObject debuggee{cx, gjs->global()};
120 [ - + ]: 20 : if (!JS_WrapObject(cx, &debuggee)) {
121 : 0 : gjs_log_exception(cx);
122 : 0 : return;
123 : : }
124 : :
125 : 20 : JS::RootedValue v_debuggee(cx, JS::ObjectValue(*debuggee));
126 : 20 : if (!JS_SetPropertyById(cx, debugger_global, gjs->atoms().debuggee(),
127 : 20 : v_debuggee) ||
128 [ + - + - ]: 40 : !JS_DefineFunctions(cx, debugger_global, debugger_funcs) ||
129 [ - + - + ]: 40 : !gjs_define_global_properties(cx, debugger_global,
130 : : GjsGlobalType::DEBUGGER, "GJS debugger",
131 : : "debugger"))
132 : 0 : gjs_log_exception(cx);
133 [ + - + - : 20 : }
+ - ]
|