all repos — litestore @ 20f1efa1f29fed91d9cbd13872537fb50eae5892

A minimalist nosql document store.

src/litestorepkg/vendor/duktape/extras/console/duk_console.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
/*
 *  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: 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_uint_t flags = (duk_uint_t) duk_get_current_magic(ctx);
	FILE *output = (flags & DUK_CONSOLE_STDOUT_ONLY) ? stdout : stderr;
	duk_idx_t n = duk_get_top(ctx);
	duk_idx_t i;

	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(output, "%s\n", duk_to_string(ctx, -1));
	if (flags & DUK_CONSOLE_FLUSH) {
		fflush(output);
	}
	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_uint_t flags_orig;

	/* If both DUK_CONSOLE_STDOUT_ONLY and DUK_CONSOLE_STDERR_ONLY where specified,
	 * just turn off DUK_CONSOLE_STDOUT_ONLY and keep DUK_CONSOLE_STDERR_ONLY.
	 */
	if ((flags & DUK_CONSOLE_STDOUT_ONLY) && (flags & DUK_CONSOLE_STDERR_ONLY)) {
	    flags &= ~DUK_CONSOLE_STDOUT_ONLY;
	}
	/* Remember the (possibly corrected) flags we received. */
	flags_orig = 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");

	flags = flags_orig;
	if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) {
	    /* No output indicators were specified; these levels go to stdout. */
	    flags |= DUK_CONSOLE_STDOUT_ONLY;
	}
	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);

	flags = flags_orig;
	if (!(flags & DUK_CONSOLE_STDOUT_ONLY) && !(flags & DUK_CONSOLE_STDERR_ONLY)) {
	    /* No output indicators were specified; these levels go to stderr. */
	    flags |= DUK_CONSOLE_STDERR_ONLY;
	}
	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 was required specifically by the
	 * DeveloperToolsWG proposal (and was implemented also by Firefox:
	 * https://bugzilla.mozilla.org/show_bug.cgi?id=629607).  This is
	 * apparently no longer the preferred way of implementing console.
	 * When Proxy is enabled, whitelist at least .toJSON() to avoid
	 * confusing JX serialization of the console object.
	 */

	if (flags & DUK_CONSOLE_PROXY_WRAPPER) {
		/* Tolerate failure to initialize Proxy wrapper in case
		 * Proxy support is disabled.
		 */
		(void) duk_peval_string_noresult(ctx,
			"(function(){"
			    "var D=function(){};"
			    "var W={toJSON:true};"  /* whitelisted */
			    "console=new Proxy(console,{"
			        "get:function(t,k){"
			            "var v=t[k];"
			            "return typeof v==='function'||W[k]?v:D;"
			        "}"
			    "});"
			"})();"
		);
	}
}