File Coverage

duk_console.c
Criterion Covered Total %
statement 86 88 97.7
branch 15 24 62.5
condition n/a
subroutine n/a
pod n/a
total 101 112 90.1


line stmt bran cond sub pod time code
1             /*
2             * Minimal 'console' binding.
3             *
4             * https://github.com/DeveloperToolsWG/console-object/blob/master/api.md
5             * https://developers.google.com/web/tools/chrome-devtools/debug/console/console-reference
6             * https://developer.mozilla.org/en/docs/Web/API/console
7             */
8              
9             #include
10             #include "duktape.h"
11             #include "duk_console.h"
12              
13             /* XXX: Add some form of log level filtering. */
14              
15             /* XXX: Should all output be written via e.g. console.write(formattedMsg)?
16             * This would make it easier for user code to redirect all console output
17             * to a custom backend.
18             */
19              
20             /* XXX: Init console object using duk_def_prop() when that call is available. */
21              
22 135           int duk_console_log(duk_context *ctx,duk_uint_t flags, const char* fmt, ...)
23             {
24 135           int ret = 0;
25             void* ourData;
26             va_list ap;
27 135           va_start(ap, fmt);
28            
29             /* Get our duk pointer for this ctx*/
30 135           duk_push_thread_stash(ctx,ctx);
31 135           duk_get_prop_string(ctx, -1, PL_NAME_CONSOLE_GENERIC_CALLBACK);
32 135           ourData = duk_get_pointer(ctx, -1);
33 135           duk_pop(ctx);
34              
35 135 50         if (ourData) {
36 135           ret = pl_console_callback(ourData,flags,fmt, ap);
37             }
38 135           va_end(ap);
39 135           return ret;
40             }
41              
42 123           static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) {
43 123           duk_uint_t flags = (duk_uint_t) duk_get_current_magic(ctx);
44 123           duk_idx_t n = duk_get_top(ctx);
45             duk_idx_t i;
46              
47 123           duk_get_global_string(ctx, "console");
48 123           duk_get_prop_string(ctx, -1, "format");
49              
50 270 100         for (i = 0; i < n; i++) {
51 147 100         if (duk_check_type_mask(ctx, i, DUK_TYPE_MASK_OBJECT)) {
52             /* Slow path formatting. */
53 16           duk_dup(ctx, -1); /* console.format */
54 16           duk_dup(ctx, i);
55 16           duk_call(ctx, 1);
56 16           duk_replace(ctx, i); /* arg[i] = console.format(arg[i]); */
57             }
58             }
59              
60 123           duk_pop_2(ctx);
61              
62 123           duk_push_string(ctx, " ");
63 123           duk_insert(ctx, 0);
64 123           duk_join(ctx, n);
65              
66 123 100         if (error_name) {
67 7           duk_push_error_object(ctx, DUK_ERR_ERROR, "%s", duk_require_string(ctx, -1));
68 7           duk_push_string(ctx, "name");
69 7           duk_push_string(ctx, error_name);
70 7           duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE); /* to get e.g. 'Trace: 1 2 3' */
71 7           duk_get_prop_string(ctx, -1, "stack");
72             }
73              
74 123           duk_console_log(ctx, flags, "%s\n", duk_to_string(ctx, -1));
75 123           return 0;
76             }
77              
78 2           static duk_ret_t duk__console_assert(duk_context *ctx) {
79 2 100         if (duk_to_boolean(ctx, 0)) {
80 1           return 0;
81             }
82 1           duk_remove(ctx, 0);
83              
84 1           return duk__console_log_helper(ctx, "AssertionError");
85             }
86              
87 110           static duk_ret_t duk__console_log(duk_context *ctx) {
88 110           return duk__console_log_helper(ctx, NULL);
89             }
90              
91 2           static duk_ret_t duk__console_trace(duk_context *ctx) {
92 2           return duk__console_log_helper(ctx, "Trace");
93             }
94              
95 2           static duk_ret_t duk__console_info(duk_context *ctx) {
96 2           return duk__console_log_helper(ctx, NULL);
97             }
98              
99 2           static duk_ret_t duk__console_warn(duk_context *ctx) {
100 2           return duk__console_log_helper(ctx, NULL);
101             }
102              
103 4           static duk_ret_t duk__console_error(duk_context *ctx) {
104 4           return duk__console_log_helper(ctx, "Error");
105             }
106              
107 2           static duk_ret_t duk__console_dir(duk_context *ctx) {
108             /* For now, just share the formatting of .log() */
109 2           return duk__console_log_helper(ctx, 0);
110             }
111              
112 3357           static void duk__console_reg_vararg_func(duk_context *ctx, duk_c_function func, const char *name, duk_uint_t flags) {
113 3357           duk_push_c_function(ctx, func, DUK_VARARGS);
114 3357           duk_push_string(ctx, "name");
115 3357           duk_push_string(ctx, name);
116 3357           duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE); /* Improve stacktraces by displaying function name */
117 3357           duk_set_magic(ctx, -1, (duk_int_t) flags);
118 3357           duk_put_prop_string(ctx, -2, name);
119 3357           }
120              
121 373           void duk_console_init(duk_context *ctx, duk_uint_t flags) {
122             duk_uint_t flags_orig;
123              
124             /* If both DUK_CONSOLE_TO_STDOUT and DUK_CONSOLE_TO_STDERR where specified,
125             * just turn off DUK_CONSOLE_TO_STDOUT and keep DUK_CONSOLE_TO_STDERR. */
126 373 50         if ((flags & DUK_CONSOLE_TO_STDOUT) &&
127 0 0         (flags & DUK_CONSOLE_TO_STDERR)) {
128 0           flags &= ~DUK_CONSOLE_TO_STDOUT;
129             }
130             /* Remember the (possibly corrected) flags we received. */
131 373           flags_orig = flags;
132              
133 373           duk_push_object(ctx);
134              
135             /* Custom function to format objects; user can replace.
136             * For now, try JX-formatting and if that fails, fall back
137             * to ToString(v).
138             */
139 373           duk_eval_string(ctx,
140             "(function (E) {"
141             "return function format(v){"
142             "try{"
143             "return E('jx',v);"
144             "}catch(e){"
145             "return String(v);" /* String() allows symbols, ToString() internal algorithm doesn't. */
146             "}"
147             "};"
148             "})(Duktape.enc)");
149 373           duk_put_prop_string(ctx, -2, "format");
150              
151 373           flags = flags_orig;
152 373 50         if (!(flags & DUK_CONSOLE_TO_STDOUT) &&
153 373 50         !(flags & DUK_CONSOLE_TO_STDERR)) {
154             /* No output indicators were specified; these levels go to stdout. */
155 373           flags |= DUK_CONSOLE_TO_STDOUT;
156             }
157 373           duk__console_reg_vararg_func(ctx, duk__console_assert, "assert", flags);
158 373           duk__console_reg_vararg_func(ctx, duk__console_log, "log", flags);
159 373           duk__console_reg_vararg_func(ctx, duk__console_log, "debug", flags); /* alias to console.log */
160 373           duk__console_reg_vararg_func(ctx, duk__console_trace, "trace", flags);
161 373           duk__console_reg_vararg_func(ctx, duk__console_info, "info", flags);
162              
163 373           flags = flags_orig;
164 373 50         if (!(flags & DUK_CONSOLE_TO_STDOUT) &&
165 373 50         !(flags & DUK_CONSOLE_TO_STDERR)) {
166             /* No output indicators were specified; these levels go to stderr. */
167 373           flags |= DUK_CONSOLE_TO_STDERR;
168             }
169 373           duk__console_reg_vararg_func(ctx, duk__console_warn, "warn", flags);
170 373           duk__console_reg_vararg_func(ctx, duk__console_error, "error", flags);
171 373           duk__console_reg_vararg_func(ctx, duk__console_error, "exception", flags); /* alias to console.error */
172 373           duk__console_reg_vararg_func(ctx, duk__console_dir, "dir", flags);
173              
174 373           duk_put_global_string(ctx, "console");
175              
176             /* Proxy wrapping: ensures any undefined console method calls are
177             * ignored silently. This is required specifically by the
178             * DeveloperToolsWG proposal (and is implemented also by Firefox:
179             * https://bugzilla.mozilla.org/show_bug.cgi?id=629607).
180             */
181              
182 373 50         if (flags & DUK_CONSOLE_PROXY_WRAPPER) {
183             /* Tolerate errors: Proxy may be disabled. */
184 373           duk_peval_string_noresult(ctx,
185             "(function(){"
186             "var D=function(){};"
187             "console=new Proxy(console,{"
188             "get:function(t,k){"
189             "var v=t[k];"
190             "return typeof v==='function'?v:D;"
191             "}"
192             "});"
193             "})();"
194             );
195             }
196 373           }