duk_print_alert.c 3.7 KB

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