123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- /*
- * Minimal 'console' binding.
- *
- * https://github.com/DeveloperToolsWG/console-object/blob/master/api.md
- * https://developers.google.com/web/tools/chrome-devtools/debug/console/console-reference
- * https://developer.mozilla.org/en/docs/Web/API/console
- */
- #include <stdio.h>
- #include <stdarg.h>
- #include "duktape.h"
- #include "duk_console.h"
- /* XXX: Add some form of log level filtering. */
- /* XXX: For now logs everything to stdout, V8/Node.js logs debug/info level
- * to stdout, warn and above to stderr. Should this extra do the same?
- */
- /* XXX: Should all output be written via e.g. console.write(formattedMsg)?
- * This would make it easier for user code to redirect all console output
- * to a custom backend.
- */
- /* XXX: Init console object using duk_def_prop() when that call is available. */
- static duk_ret_t duk__console_log_helper(duk_context *ctx, const char *error_name) {
- duk_idx_t i, n;
- duk_uint_t flags;
- flags = (duk_uint_t) duk_get_current_magic(ctx);
- n = duk_get_top(ctx);
- duk_get_global_string(ctx, "console");
- duk_get_prop_string(ctx, -1, "format");
- for (i = 0; i < n; i++) {
- if (duk_check_type_mask(ctx, i, DUK_TYPE_MASK_OBJECT)) {
- /* Slow path formatting. */
- duk_dup(ctx, -1); /* console.format */
- duk_dup(ctx, i);
- duk_call(ctx, 1);
- duk_replace(ctx, i); /* arg[i] = console.format(arg[i]); */
- }
- }
- duk_pop_2(ctx);
- duk_push_string(ctx, " ");
- duk_insert(ctx, 0);
- duk_join(ctx, n);
- if (error_name) {
- duk_push_error_object(ctx, DUK_ERR_ERROR, "%s", duk_require_string(ctx, -1));
- duk_push_string(ctx, "name");
- duk_push_string(ctx, error_name);
- duk_def_prop(ctx, -3, DUK_DEFPROP_FORCE | DUK_DEFPROP_HAVE_VALUE); /* to get e.g. 'Trace: 1 2 3' */
- duk_get_prop_string(ctx, -1, "stack");
- }
- fprintf(stdout, "%s\n", duk_to_string(ctx, -1));
- if (flags & DUK_CONSOLE_FLUSH) {
- fflush(stdout);
- }
- return 0;
- }
- static duk_ret_t duk__console_assert(duk_context *ctx) {
- if (duk_to_boolean(ctx, 0)) {
- return 0;
- }
- duk_remove(ctx, 0);
- return duk__console_log_helper(ctx, "AssertionError");
- }
- static duk_ret_t duk__console_log(duk_context *ctx) {
- return duk__console_log_helper(ctx, NULL);
- }
- static duk_ret_t duk__console_trace(duk_context *ctx) {
- return duk__console_log_helper(ctx, "Trace");
- }
- static duk_ret_t duk__console_info(duk_context *ctx) {
- return duk__console_log_helper(ctx, NULL);
- }
- static duk_ret_t duk__console_warn(duk_context *ctx) {
- return duk__console_log_helper(ctx, NULL);
- }
- static duk_ret_t duk__console_error(duk_context *ctx) {
- return duk__console_log_helper(ctx, "Error");
- }
- static duk_ret_t duk__console_dir(duk_context *ctx) {
- /* For now, just share the formatting of .log() */
- return duk__console_log_helper(ctx, 0);
- }
- static void duk__console_reg_vararg_func(duk_context *ctx, duk_c_function func, const char *name, duk_uint_t flags) {
- duk_push_c_function(ctx, func, DUK_VARARGS);
- duk_push_string(ctx, "name");
- duk_push_string(ctx, name);
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE); /* Improve stacktraces by displaying function name */
- duk_set_magic(ctx, -1, (duk_int_t) flags);
- duk_put_prop_string(ctx, -2, name);
- }
- void duk_console_init(duk_context *ctx, duk_uint_t flags) {
- duk_push_object(ctx);
- /* Custom function to format objects; user can replace.
- * For now, try JX-formatting and if that fails, fall back
- * to ToString(v).
- */
- duk_eval_string(ctx,
- "(function (E) {"
- "return function format(v){"
- "try{"
- "return E('jx',v);"
- "}catch(e){"
- "return String(v);" /* String() allows symbols, ToString() internal algorithm doesn't. */
- "}"
- "};"
- "})(Duktape.enc)");
- duk_put_prop_string(ctx, -2, "format");
- duk__console_reg_vararg_func(ctx, duk__console_assert, "assert", flags);
- duk__console_reg_vararg_func(ctx, duk__console_log, "log", flags);
- duk__console_reg_vararg_func(ctx, duk__console_log, "debug", flags); /* alias to console.log */
- duk__console_reg_vararg_func(ctx, duk__console_trace, "trace", flags);
- duk__console_reg_vararg_func(ctx, duk__console_info, "info", flags);
- duk__console_reg_vararg_func(ctx, duk__console_warn, "warn", flags);
- duk__console_reg_vararg_func(ctx, duk__console_error, "error", flags);
- duk__console_reg_vararg_func(ctx, duk__console_error, "exception", flags); /* alias to console.error */
- duk__console_reg_vararg_func(ctx, duk__console_dir, "dir", flags);
- duk_put_global_string(ctx, "console");
- /* Proxy wrapping: ensures any undefined console method calls are
- * ignored silently. This is required specifically by the
- * DeveloperToolsWG proposal (and is implemented also by Firefox:
- * https://bugzilla.mozilla.org/show_bug.cgi?id=629607).
- */
- if (flags & DUK_CONSOLE_PROXY_WRAPPER) {
- /* Tolerate errors: Proxy may be disabled. */
- duk_peval_string_noresult(ctx,
- "(function(){"
- "var D=function(){};"
- "console=new Proxy(console,{"
- "get:function(t,k){"
- "var v=t[k];"
- "return typeof v==='function'?v:D;"
- "}"
- "});"
- "})();"
- );
- }
- }
|