1 module duk_extras.print_alert; 2 3 /* 4 * Duktape 1.x compatible print() and alert() bindings. 5 */ 6 7 import core.stdc.stdio; 8 import core.stdc..string; 9 10 import duktape; 11 12 enum DUK_PRINT_ALERT_FLUSH = true; /* Flush after stdout/stderr write (Duktape 1.x: yes) */ 13 enum DUK_PRINT_ALERT_SMALL = false; /* Prefer smaller footprint (but slower and more memory churn) */ 14 15 private duk_ret_t duk__print_alert_helper_small(duk_context *ctx, FILE *fh) { 16 duk_idx_t nargs; 17 const(duk_uint8_t) *buf; 18 duk_size_t sz_buf; 19 20 nargs = duk_get_top(ctx); 21 22 /* If argument count is 1 and first argument is a buffer, write the buffer 23 * as raw data into the file without a newline; this allows exact control 24 * over stdout/stderr without an additional entrypoint (useful for now). 25 * Otherwise current print/alert semantics are to ToString() coerce 26 * arguments, join them with a single space, and append a newline. 27 */ 28 29 if (nargs == 1 && duk_is_buffer(ctx, 0)) { 30 buf = cast(const(duk_uint8_t) *) duk_get_buffer(ctx, 0, &sz_buf); 31 fwrite(cast(const void *) buf, 1, cast(size_t) sz_buf, fh); 32 } else { 33 duk_push_string(ctx, " "); 34 duk_insert(ctx, 0); 35 duk_concat(ctx, nargs); 36 fprintf(fh, "%s\n", duk_require_string(ctx, -1)); 37 } 38 39 static if (DUK_PRINT_ALERT_FLUSH) { 40 fflush(fh); 41 } 42 43 return 0; 44 } 45 46 /* Faster, less churn, higher footprint option. */ 47 private duk_ret_t duk__print_alert_helper(duk_context *ctx, FILE *fh) { 48 duk_idx_t nargs; 49 const(duk_uint8_t) *buf; 50 duk_size_t sz_buf; 51 const char nl = cast(const char) '\n'; 52 duk_uint8_t[256] buf_stack; 53 54 nargs = duk_get_top(ctx); 55 56 /* If argument count is 1 and first argument is a buffer, write the buffer 57 * as raw data into the file without a newline; this allows exact control 58 * over stdout/stderr without an additional entrypoint (useful for now). 59 * Otherwise current print/alert semantics are to ToString() coerce 60 * arguments, join them with a single space, and append a newline. 61 */ 62 63 if (nargs == 1 && duk_is_buffer(ctx, 0)) { 64 buf = cast(const(duk_uint8_t) *) duk_get_buffer(ctx, 0, &sz_buf); 65 } else if (nargs > 0) { 66 duk_idx_t i; 67 duk_size_t sz_str; 68 const(duk_uint8_t) *p_str; 69 duk_uint8_t *p; 70 71 sz_buf = cast(duk_size_t) nargs; /* spaces (nargs - 1) + newline */ 72 for (i = 0; i < nargs; i++) { 73 duk_to_lstring(ctx, i, &sz_str); 74 sz_buf += sz_str; 75 } 76 77 if (sz_buf <= buf_stack.sizeof) { 78 p = cast(duk_uint8_t *) buf_stack; 79 } else { 80 p = cast(duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf); 81 } 82 83 buf = cast(const(duk_uint8_t) *) p; 84 for (i = 0; i < nargs; i++) { 85 p_str = cast(const(duk_uint8_t) *) duk_get_lstring(ctx, i, &sz_str); 86 memcpy(cast(void *) p, cast(const void *) p_str, sz_str); 87 p += sz_str; 88 *p++ = cast(duk_uint8_t) (i == nargs - 1 ? '\n' : ' '); 89 } 90 } else { 91 buf = cast(const(duk_uint8_t) *) &nl; 92 sz_buf = 1; 93 } 94 95 /* 'buf' contains the string to write, 'sz_buf' contains the length 96 * (which may be zero). 97 */ 98 99 if (sz_buf > 0) { 100 fwrite(cast(const void *) buf, 1, cast(size_t) sz_buf, fh); 101 static if (DUK_PRINT_ALERT_FLUSH) { 102 fflush(fh); 103 } 104 } 105 106 return 0; 107 } 108 109 extern(C) private duk_ret_t duk__print(duk_context *ctx) { 110 if (DUK_PRINT_ALERT_SMALL) 111 return duk__print_alert_helper_small(ctx, stdout); 112 else 113 return duk__print_alert_helper(ctx, stdout); 114 } 115 116 extern(C) private duk_ret_t duk__alert(duk_context *ctx) { 117 if (DUK_PRINT_ALERT_SMALL) 118 return duk__print_alert_helper_small(ctx, stderr); 119 else 120 return duk__print_alert_helper(ctx, stderr); 121 } 122 123 void duk_print_alert_init(duk_context *ctx, duk_uint_t flags) { 124 //(void) flags; /* unused at the moment */ 125 126 /* XXX: use duk_def_prop_list(). */ 127 duk_push_global_object(ctx); 128 duk_push_string(ctx, "print"); 129 duk_push_c_function(ctx, &duk__print, DUK_VARARGS); 130 duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE); 131 duk_push_string(ctx, "alert"); 132 duk_push_c_function(ctx, &duk__alert, DUK_VARARGS); 133 duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_SET_WRITABLE | DUK_DEFPROP_SET_CONFIGURABLE); 134 duk_pop(ctx); 135 }