]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/opentelemetry-cpp/third_party/prometheus-cpp/3rdparty/civetweb/src/third_party/duktape-1.5.2/examples/debug-trans-dvalue/duk_trans_dvalue.c
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / jaegertracing / opentelemetry-cpp / third_party / prometheus-cpp / 3rdparty / civetweb / src / third_party / duktape-1.5.2 / examples / debug-trans-dvalue / duk_trans_dvalue.c
1 /*
2 * Example debug transport with a local debug message encoder/decoder.
3 *
4 * Provides a "received dvalue" callback for a fully parsed dvalue (user
5 * code frees dvalue) and a "cooperate" callback for e.g. UI integration.
6 * There are a few other callbacks. See test.c for usage examples.
7 *
8 * This transport implementation is not multithreaded which means that:
9 *
10 * - Callbacks to "received dvalue" callback come from the Duktape thread,
11 * either during normal execution or from duk_debugger_cooperate().
12 *
13 * - Calls into duk_trans_dvalue_send() must be made from the callbacks
14 * provided (e.g. "received dvalue" or "cooperate") which use the active
15 * Duktape thread.
16 *
17 * - The only exception to this is when Duktape is idle: you can then call
18 * duk_trans_dvalue_send() from any thread (only one thread at a time).
19 * When you next call into Duktape or call duk_debugger_cooperate(), the
20 * queued data will be read and processed by Duktape.
21 *
22 * There are functions for creating and freeing values; internally they use
23 * malloc() and free() for memory management. Duktape heap alloc functions
24 * are not used to minimize disturbances to the Duktape heap under debugging.
25 *
26 * Doesn't depend on C99 types; assumes "int" is at least 32 bits, and makes
27 * a few assumptions about format specifiers.
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "duktape.h"
35 #include "duk_trans_dvalue.h"
36
37 /* Define to enable debug prints to stderr. */
38 #if 0
39 #define DEBUG_PRINTS
40 #endif
41
42 /* Define to enable error prints to stderr. */
43 #if 1
44 #define ERROR_PRINTS
45 #endif
46
47 /*
48 * Dvalue handling
49 */
50
51 duk_dvalue *duk_dvalue_alloc(void) {
52 duk_dvalue *dv = (duk_dvalue *) malloc(sizeof(duk_dvalue));
53 if (dv) {
54 memset((void *) dv, 0, sizeof(duk_dvalue));
55 dv->buf = NULL;
56 }
57 return dv;
58 }
59
60 void duk_dvalue_free(duk_dvalue *dv) {
61 if (dv) {
62 free(dv->buf); /* tolerates NULL */
63 dv->buf = NULL;
64 free(dv);
65 }
66 }
67
68 static void duk__dvalue_bufesc(duk_dvalue *dv, char *buf, size_t maxbytes, int stresc) {
69 size_t i, limit;
70
71 *buf = (char) 0;
72 limit = dv->len > maxbytes ? maxbytes : dv->len;
73 for (i = 0; i < limit; i++) {
74 unsigned char c = dv->buf[i];
75 if (stresc) {
76 if (c >= 0x20 && c <= 0x7e && c != (char) '"' && c != (char) '\'') {
77 sprintf(buf, "%c", c);
78 buf++;
79 } else {
80 sprintf(buf, "\\x%02x", (unsigned int) c);
81 buf += 4;
82 }
83 } else {
84 sprintf(buf, "%02x", (unsigned int) c);
85 buf += 2;
86 }
87 }
88 if (dv->len > maxbytes) {
89 sprintf(buf, "...");
90 buf += 3;
91 }
92 }
93
94 /* Caller must provide a buffer at least DUK_DVALUE_TOSTRING_BUFLEN in size. */
95 void duk_dvalue_to_string(duk_dvalue *dv, char *buf) {
96 char hexbuf[32 * 4 + 4]; /* 32 hex encoded or \xXX escaped bytes, possible "...", NUL */
97
98 if (!dv) {
99 sprintf(buf, "NULL");
100 return;
101 }
102
103 switch (dv->tag) {
104 case DUK_DVALUE_EOM:
105 sprintf(buf, "EOM");
106 break;
107 case DUK_DVALUE_REQ:
108 sprintf(buf, "REQ");
109 break;
110 case DUK_DVALUE_REP:
111 sprintf(buf, "REP");
112 break;
113 case DUK_DVALUE_ERR:
114 sprintf(buf, "ERR");
115 break;
116 case DUK_DVALUE_NFY:
117 sprintf(buf, "NFY");
118 break;
119 case DUK_DVALUE_INTEGER:
120 sprintf(buf, "%d", dv->i);
121 break;
122 case DUK_DVALUE_STRING:
123 duk__dvalue_bufesc(dv, hexbuf, 32, 1);
124 sprintf(buf, "str:%ld:\"%s\"", (long) dv->len, hexbuf);
125 break;
126 case DUK_DVALUE_BUFFER:
127 duk__dvalue_bufesc(dv, hexbuf, 32, 0);
128 sprintf(buf, "buf:%ld:%s", (long) dv->len, hexbuf);
129 break;
130 case DUK_DVALUE_UNUSED:
131 sprintf(buf, "undefined");
132 break;
133 case DUK_DVALUE_UNDEFINED:
134 sprintf(buf, "undefined");
135 break;
136 case DUK_DVALUE_NULL:
137 sprintf(buf, "null");
138 break;
139 case DUK_DVALUE_TRUE:
140 sprintf(buf, "true");
141 break;
142 case DUK_DVALUE_FALSE:
143 sprintf(buf, "false");
144 break;
145 case DUK_DVALUE_NUMBER:
146 if (fpclassify(dv->d) == FP_ZERO) {
147 if (signbit(dv->d)) {
148 sprintf(buf, "-0");
149 } else {
150 sprintf(buf, "0");
151 }
152 } else {
153 sprintf(buf, "%lg", dv->d);
154 }
155 break;
156 case DUK_DVALUE_OBJECT:
157 duk__dvalue_bufesc(dv, hexbuf, 32, 0);
158 sprintf(buf, "obj:%d:%s", (int) dv->i, hexbuf);
159 break;
160 case DUK_DVALUE_POINTER:
161 duk__dvalue_bufesc(dv, hexbuf, 32, 0);
162 sprintf(buf, "ptr:%s", hexbuf);
163 break;
164 case DUK_DVALUE_LIGHTFUNC:
165 duk__dvalue_bufesc(dv, hexbuf, 32, 0);
166 sprintf(buf, "lfunc:%04x:%s", (unsigned int) dv->i, hexbuf);
167 break;
168 case DUK_DVALUE_HEAPPTR:
169 duk__dvalue_bufesc(dv, hexbuf, 32, 0);
170 sprintf(buf, "heapptr:%s", hexbuf);
171 break;
172 default:
173 sprintf(buf, "unknown:%d", (int) dv->tag);
174 }
175 }
176
177 duk_dvalue *duk_dvalue_make_tag(int tag) {
178 duk_dvalue *dv = duk_dvalue_alloc();
179 if (!dv) { return NULL; }
180 dv->tag = tag;
181 return dv;
182 }
183
184 duk_dvalue *duk_dvalue_make_tag_int(int tag, int intval) {
185 duk_dvalue *dv = duk_dvalue_alloc();
186 if (!dv) { return NULL; }
187 dv->tag = tag;
188 dv->i = intval;
189 return dv;
190 }
191
192 duk_dvalue *duk_dvalue_make_tag_double(int tag, double dblval) {
193 duk_dvalue *dv = duk_dvalue_alloc();
194 if (!dv) { return NULL; }
195 dv->tag = tag;
196 dv->d = dblval;
197 return dv;
198 }
199
200 duk_dvalue *duk_dvalue_make_tag_data(int tag, const char *buf, size_t len) {
201 unsigned char *p;
202 duk_dvalue *dv = duk_dvalue_alloc();
203 if (!dv) { return NULL; }
204 /* Alloc size is len + 1 so that a NUL terminator is always
205 * guaranteed which is convenient, e.g. you can printf() the
206 * value safely.
207 */
208 p = (unsigned char *) malloc(len + 1);
209 if (!p) {
210 free(dv);
211 return NULL;
212 }
213 memcpy((void *) p, (const void *) buf, len);
214 p[len] = (unsigned char) 0;
215 dv->tag = tag;
216 dv->buf = p;
217 dv->len = len;
218 return dv;
219 }
220
221 duk_dvalue *duk_dvalue_make_tag_int_data(int tag, int intval, const char *buf, size_t len) {
222 duk_dvalue *dv = duk_dvalue_make_tag_data(tag, buf, len);
223 if (!dv) { return NULL; }
224 dv->i = intval;
225 return dv;
226 }
227
228 /*
229 * Dvalue transport handling
230 */
231
232 static void duk__trans_dvalue_double_byteswap(duk_trans_dvalue_ctx *ctx, volatile unsigned char *p) {
233 unsigned char t;
234
235 /* Portable IEEE double byteswap. Relies on runtime detection of
236 * host endianness.
237 */
238
239 if (ctx->double_byteorder == 0) {
240 /* little endian */
241 t = p[0]; p[0] = p[7]; p[7] = t;
242 t = p[1]; p[1] = p[6]; p[6] = t;
243 t = p[2]; p[2] = p[5]; p[5] = t;
244 t = p[3]; p[3] = p[4]; p[4] = t;
245 } else if (ctx->double_byteorder == 1) {
246 /* big endian: ok as is */
247 ;
248 } else {
249 /* mixed endian */
250 t = p[0]; p[0] = p[3]; p[3] = t;
251 t = p[1]; p[1] = p[2]; p[2] = t;
252 t = p[4]; p[4] = p[7]; p[7] = t;
253 t = p[5]; p[5] = p[6]; p[6] = t;
254 }
255 }
256
257 static unsigned int duk__trans_dvalue_parse_u32(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
258 /* Integers are network endian, read back into host format in
259 * a portable manner.
260 */
261 (void) ctx;
262 return (((unsigned int) p[0]) << 24) +
263 (((unsigned int) p[1]) << 16) +
264 (((unsigned int) p[2]) << 8) +
265 (((unsigned int) p[3]) << 0);
266 }
267
268 static int duk__trans_dvalue_parse_i32(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
269 /* Portable sign handling, doesn't assume 'int' is exactly 32 bits
270 * like a direct cast would.
271 */
272 unsigned int tmp = duk__trans_dvalue_parse_u32(ctx, p);
273 if (tmp & 0x80000000UL) {
274 return -((int) ((tmp ^ 0xffffffffUL) + 1UL));
275 } else {
276 return tmp;
277 }
278 }
279
280 static unsigned int duk__trans_dvalue_parse_u16(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
281 /* Integers are network endian, read back into host format. */
282 (void) ctx;
283 return (((unsigned int) p[0]) << 8) +
284 (((unsigned int) p[1]) << 0);
285 }
286
287 static double duk__trans_dvalue_parse_double(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
288 /* IEEE doubles are network endian, read back into host format. */
289 volatile union {
290 double d;
291 unsigned char b[8];
292 } u;
293 memcpy((void *) u.b, (const void *) p, 8);
294 duk__trans_dvalue_double_byteswap(ctx, u.b);
295 return u.d;
296 }
297
298 static unsigned char *duk__trans_dvalue_encode_u32(duk_trans_dvalue_ctx *ctx, unsigned char *p, unsigned int val) {
299 /* Integers are written in network endian format. */
300 (void) ctx;
301 *p++ = (unsigned char) ((val >> 24) & 0xff);
302 *p++ = (unsigned char) ((val >> 16) & 0xff);
303 *p++ = (unsigned char) ((val >> 8) & 0xff);
304 *p++ = (unsigned char) (val & 0xff);
305 return p;
306 }
307
308 static unsigned char *duk__trans_dvalue_encode_i32(duk_trans_dvalue_ctx *ctx, unsigned char *p, int val) {
309 return duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) val & 0xffffffffUL);
310 }
311
312 static unsigned char *duk__trans_dvalue_encode_u16(duk_trans_dvalue_ctx *ctx, unsigned char *p, unsigned int val) {
313 /* Integers are written in network endian format. */
314 (void) ctx;
315 *p++ = (unsigned char) ((val >> 8) & 0xff);
316 *p++ = (unsigned char) (val & 0xff);
317 return p;
318 }
319
320 static unsigned char *duk__trans_dvalue_encode_double(duk_trans_dvalue_ctx *ctx, unsigned char *p, double val) {
321 /* IEEE doubles are written in network endian format. */
322 volatile union {
323 double d;
324 unsigned char b[8];
325 } u;
326 u.d = val;
327 duk__trans_dvalue_double_byteswap(ctx, u.b);
328 memcpy((void *) p, (const void *) u.b, 8);
329 p += 8;
330 return p;
331 }
332
333 static unsigned char *duk__trans_buffer_ensure(duk_trans_buffer *dbuf, size_t space) {
334 size_t avail;
335 size_t used;
336 size_t new_size;
337 void *new_alloc;
338
339 used = dbuf->write_offset;
340 avail = dbuf->alloc_size - dbuf->write_offset;
341
342 if (avail >= space) {
343 if (avail - space > 256) {
344 /* Too big, resize so that we reclaim memory if we have just
345 * received a large string/buffer value.
346 */
347 goto do_realloc;
348 }
349 } else {
350 /* Too small, resize. */
351 goto do_realloc;
352 }
353
354 return dbuf->base + dbuf->write_offset;
355
356 do_realloc:
357 new_size = used + space + 256; /* some extra to reduce resizes */
358 new_alloc = realloc(dbuf->base, new_size);
359 if (new_alloc) {
360 dbuf->base = (unsigned char *) new_alloc;
361 dbuf->alloc_size = new_size;
362 #if defined(DEBUG_PRINTS)
363 fprintf(stderr, "%s: resized buffer %p to %ld bytes, read_offset=%ld, write_offset=%ld\n",
364 __func__, (void *) dbuf, (long) new_size, (long) dbuf->read_offset, (long) dbuf->write_offset);
365 fflush(stderr);
366 #endif
367 return dbuf->base + dbuf->write_offset;
368 } else {
369 return NULL;
370 }
371 }
372
373 /* When read_offset is large enough, "rebase" buffer by deleting already
374 * read data and updating offsets.
375 */
376 static void duk__trans_buffer_rebase(duk_trans_buffer *dbuf) {
377 if (dbuf->read_offset > 64) {
378 #if defined(DEBUG_PRINTS)
379 fprintf(stderr, "%s: rebasing buffer %p, read_offset=%ld, write_offset=%ld\n",
380 __func__, (void *) dbuf, (long) dbuf->read_offset, (long) dbuf->write_offset);
381 fflush(stderr);
382 #endif
383 if (dbuf->write_offset > dbuf->read_offset) {
384 memmove((void *) dbuf->base, (const void *) (dbuf->base + dbuf->read_offset), dbuf->write_offset - dbuf->read_offset);
385 }
386 dbuf->write_offset -= dbuf->read_offset;
387 dbuf->read_offset = 0;
388 }
389 }
390
391 duk_trans_dvalue_ctx *duk_trans_dvalue_init(void) {
392 volatile union {
393 double d;
394 unsigned char b[8];
395 } u;
396 duk_trans_dvalue_ctx *ctx = NULL;
397
398 ctx = (duk_trans_dvalue_ctx *) malloc(sizeof(duk_trans_dvalue_ctx));
399 if (!ctx) { goto fail; }
400 memset((void *) ctx, 0, sizeof(duk_trans_dvalue_ctx));
401 ctx->received = NULL;
402 ctx->cooperate = NULL;
403 ctx->handshake = NULL;
404 ctx->detached = NULL;
405 ctx->send_buf.base = NULL;
406 ctx->recv_buf.base = NULL;
407
408 ctx->send_buf.base = malloc(256);
409 if (!ctx->send_buf.base) { goto fail; }
410 ctx->send_buf.alloc_size = 256;
411
412 ctx->recv_buf.base = malloc(256);
413 if (!ctx->recv_buf.base) { goto fail; }
414 ctx->recv_buf.alloc_size = 256;
415
416 /* IEEE double byte order, detect at run time (could also use
417 * preprocessor defines but that's verbose to make portable).
418 *
419 * >>> struct.unpack('>d', '1122334455667788'.decode('hex'))
420 * (3.841412024471731e-226,)
421 * >>> struct.unpack('>d', '8877665544332211'.decode('hex'))
422 * (-7.086876636573014e-268,)
423 * >>> struct.unpack('>d', '4433221188776655'.decode('hex'))
424 * (3.5294303071877444e+20,)
425 */
426 u.b[0] = 0x11; u.b[1] = 0x22; u.b[2] = 0x33; u.b[3] = 0x44;
427 u.b[4] = 0x55; u.b[5] = 0x66; u.b[6] = 0x77; u.b[7] = 0x88;
428 if (u.d < 0.0) {
429 ctx->double_byteorder = 0; /* little endian */
430 } else if (u.d < 1.0) {
431 ctx->double_byteorder = 1; /* big endian */
432 } else {
433 ctx->double_byteorder = 2; /* mixed endian (arm) */
434 }
435 #if defined(DEBUG_PRINTS)
436 fprintf(stderr, "double endianness test value is %lg -> byteorder %d\n",
437 u.d, ctx->double_byteorder);
438 fflush(stderr);
439 #endif
440
441 return ctx;
442
443 fail:
444 if (ctx) {
445 free(ctx->recv_buf.base); /* tolerates NULL */
446 free(ctx->send_buf.base); /* tolerates NULL */
447 free(ctx);
448 }
449 return NULL;
450 }
451
452 void duk_trans_dvalue_free(duk_trans_dvalue_ctx *ctx) {
453 if (ctx) {
454 free(ctx->send_buf.base); /* tolerates NULL */
455 free(ctx->recv_buf.base); /* tolerates NULL */
456 free(ctx);
457 }
458 }
459
460 void duk_trans_dvalue_send(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) {
461 unsigned char *p;
462
463 /* Convert argument dvalue into Duktape debug protocol format.
464 * Literal constants are used here for the debug protocol,
465 * e.g. initial byte 0x02 is REP, see doc/debugger.rst.
466 */
467
468 #if defined(DEBUG_PRINTS)
469 {
470 char buf[DUK_DVALUE_TOSTRING_BUFLEN];
471 duk_dvalue_to_string(dv, buf);
472 fprintf(stderr, "%s: sending dvalue: %s\n", __func__, buf);
473 fflush(stderr);
474 }
475 #endif
476
477 switch (dv->tag) {
478 case DUK_DVALUE_EOM: {
479 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
480 if (!p) { goto alloc_error; }
481 *p++ = 0x00;
482 ctx->send_buf.write_offset += 1;
483 break;
484 }
485 case DUK_DVALUE_REQ: {
486 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
487 if (!p) { goto alloc_error; }
488 *p++ = 0x01;
489 ctx->send_buf.write_offset += 1;
490 break;
491 }
492 case DUK_DVALUE_REP: {
493 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
494 if (!p) { goto alloc_error; }
495 *p++ = 0x02;
496 ctx->send_buf.write_offset += 1;
497 break;
498 }
499 case DUK_DVALUE_ERR: {
500 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
501 if (!p) { goto alloc_error; }
502 *p++ = 0x03;
503 ctx->send_buf.write_offset += 1;
504 break;
505 }
506 case DUK_DVALUE_NFY: {
507 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
508 if (!p) { goto alloc_error; }
509 *p++ = 0x04;
510 ctx->send_buf.write_offset += 1;
511 break;
512 }
513 case DUK_DVALUE_INTEGER: {
514 int i = dv->i;
515 if (i >= 0 && i <= 63) {
516 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
517 if (!p) { goto alloc_error; }
518 *p++ = (unsigned char) (0x80 + i);
519 ctx->send_buf.write_offset += 1;
520 } else if (i >= 0 && i <= 16383L) {
521 p = duk__trans_buffer_ensure(&ctx->send_buf, 2);
522 if (!p) { goto alloc_error; }
523 *p++ = (unsigned char) (0xc0 + (i >> 8));
524 *p++ = (unsigned char) (i & 0xff);
525 ctx->send_buf.write_offset += 2;
526 } else if (i >= -0x80000000L && i <= 0x7fffffffL) { /* Harmless warning on some platforms (re: range) */
527 p = duk__trans_buffer_ensure(&ctx->send_buf, 5);
528 if (!p) { goto alloc_error; }
529 *p++ = 0x10;
530 p = duk__trans_dvalue_encode_i32(ctx, p, i);
531 ctx->send_buf.write_offset += 5;
532 } else {
533 goto dvalue_error;
534 }
535 break;
536 }
537 case DUK_DVALUE_STRING: {
538 size_t i = dv->len;
539 if (i <= 0x1fUL) {
540 p = duk__trans_buffer_ensure(&ctx->send_buf, 1 + i);
541 if (!p) { goto alloc_error; }
542 *p++ = (unsigned char) (0x60 + i);
543 memcpy((void *) p, (const void *) dv->buf, i);
544 p += i;
545 ctx->send_buf.write_offset += 1 + i;
546 } else if (i <= 0xffffUL) {
547 p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i);
548 if (!p) { goto alloc_error; }
549 *p++ = 0x12;
550 p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) i);
551 memcpy((void *) p, (const void *) dv->buf, i);
552 p += i;
553 ctx->send_buf.write_offset += 3 + i;
554 } else if (i <= 0xffffffffUL) {
555 p = duk__trans_buffer_ensure(&ctx->send_buf, 5 + i);
556 if (!p) { goto alloc_error; }
557 *p++ = 0x11;
558 p = duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) i);
559 memcpy((void *) p, (const void *) dv->buf, i);
560 p += i;
561 ctx->send_buf.write_offset += 5 + i;
562 } else {
563 goto dvalue_error;
564 }
565 break;
566 }
567 case DUK_DVALUE_BUFFER: {
568 size_t i = dv->len;
569 if (i <= 0xffffUL) {
570 p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i);
571 if (!p) { goto alloc_error; }
572 *p++ = 0x14;
573 p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) i);
574 memcpy((void *) p, (const void *) dv->buf, i);
575 p += i;
576 ctx->send_buf.write_offset += 3 + i;
577 } else if (i <= 0xffffffffUL) {
578 p = duk__trans_buffer_ensure(&ctx->send_buf, 5 + i);
579 if (!p) { goto alloc_error; }
580 *p++ = 0x13;
581 p = duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) i);
582 memcpy((void *) p, (const void *) dv->buf, i);
583 p += i;
584 ctx->send_buf.write_offset += 5 + i;
585 } else {
586 goto dvalue_error;
587 }
588 break;
589 }
590 case DUK_DVALUE_UNUSED: {
591 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
592 if (!p) { goto alloc_error; }
593 *p++ = 0x15;
594 ctx->send_buf.write_offset += 1;
595 break;
596 }
597 case DUK_DVALUE_UNDEFINED: {
598 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
599 if (!p) { goto alloc_error; }
600 *p++ = 0x16;
601 ctx->send_buf.write_offset += 1;
602 break;
603 }
604 case DUK_DVALUE_NULL: {
605 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
606 if (!p) { goto alloc_error; }
607 *p++ = 0x17;
608 ctx->send_buf.write_offset += 1;
609 break;
610 }
611 case DUK_DVALUE_TRUE: {
612 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
613 if (!p) { goto alloc_error; }
614 *p++ = 0x18;
615 ctx->send_buf.write_offset += 1;
616 break;
617 }
618 case DUK_DVALUE_FALSE: {
619 p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
620 if (!p) { goto alloc_error; }
621 *p++ = 0x19;
622 ctx->send_buf.write_offset += 1;
623 break;
624 }
625 case DUK_DVALUE_NUMBER: {
626 p = duk__trans_buffer_ensure(&ctx->send_buf, 9);
627 if (!p) { goto alloc_error; }
628 *p++ = 0x1a;
629 p = duk__trans_dvalue_encode_double(ctx, p, dv->d);
630 ctx->send_buf.write_offset += 9;
631 break;
632 }
633 case DUK_DVALUE_OBJECT: {
634 size_t i = dv->len;
635 if (i <= 0xffUL && dv->i >= 0 && dv->i <= 0xffL) {
636 p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i);
637 if (!p) { goto alloc_error; }
638 *p++ = 0x1b;
639 *p++ = (unsigned char) dv->i;
640 *p++ = (unsigned char) i;
641 memcpy((void *) p, (const void *) dv->buf, i);
642 ctx->send_buf.write_offset += 3 + i;
643 } else {
644 goto dvalue_error;
645 }
646 break;
647 }
648 case DUK_DVALUE_POINTER: {
649 size_t i = dv->len;
650 if (i <= 0xffUL) {
651 p = duk__trans_buffer_ensure(&ctx->send_buf, 2 + i);
652 if (!p) { goto alloc_error; }
653 *p++ = 0x1c;
654 *p++ = (unsigned char) i;
655 memcpy((void *) p, (const void *) dv->buf, i);
656 ctx->send_buf.write_offset += 2 + i;
657 } else {
658 goto dvalue_error;
659 }
660 break;
661 }
662 case DUK_DVALUE_LIGHTFUNC: {
663 size_t i = dv->len;
664 if (i <= 0xffUL && dv->i >= 0 && dv->i <= 0xffffL) {
665 p = duk__trans_buffer_ensure(&ctx->send_buf, 4 + i);
666 if (!p) { goto alloc_error; }
667 *p++ = 0x1d;
668 p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) dv->i);
669 *p++ = (unsigned char) i;
670 memcpy((void *) p, (const void *) dv->buf, i);
671 ctx->send_buf.write_offset += 4 + i;
672 } else {
673 goto dvalue_error;
674 }
675 break;
676 }
677 case DUK_DVALUE_HEAPPTR: {
678 size_t i = dv->len;
679 if (i <= 0xffUL) {
680 p = duk__trans_buffer_ensure(&ctx->send_buf, 2 + i);
681 if (!p) { goto alloc_error; }
682 *p++ = 0x1e;
683 *p++ = (unsigned char) i;
684 memcpy((void *) p, (const void *) dv->buf, i);
685 ctx->send_buf.write_offset += 2 + i;
686 } else {
687 goto dvalue_error;
688 }
689 break;
690 }
691 default: {
692 goto dvalue_error;
693 }
694 } /* end switch */
695
696 return;
697
698 dvalue_error:
699 #if defined(ERROR_PRINTS)
700 fprintf(stderr, "%s: internal error, argument dvalue is invalid\n", __func__);
701 fflush(stdout);
702 #endif
703 return;
704
705 alloc_error:
706 #if defined(ERROR_PRINTS)
707 fprintf(stderr, "%s: internal error, failed to allocate space for write\n", __func__);
708 fflush(stdout);
709 #endif
710 return;
711 }
712
713 static void duk__trans_dvalue_send_and_free(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) {
714 if (!dv) { return; }
715 duk_trans_dvalue_send(ctx, dv);
716 duk_dvalue_free(dv);
717 }
718
719 void duk_trans_dvalue_send_eom(duk_trans_dvalue_ctx *ctx) {
720 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_EOM));
721 }
722
723 void duk_trans_dvalue_send_req(duk_trans_dvalue_ctx *ctx) {
724 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_REQ));
725 }
726
727 void duk_trans_dvalue_send_rep(duk_trans_dvalue_ctx *ctx) {
728 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_REP));
729 }
730
731 void duk_trans_dvalue_send_err(duk_trans_dvalue_ctx *ctx) {
732 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_ERR));
733 }
734
735 void duk_trans_dvalue_send_nfy(duk_trans_dvalue_ctx *ctx) {
736 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_NFY));
737 }
738
739 void duk_trans_dvalue_send_integer(duk_trans_dvalue_ctx *ctx, int val) {
740 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, val));
741 }
742
743 void duk_trans_dvalue_send_string(duk_trans_dvalue_ctx *ctx, const char *str) {
744 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_STRING, str, strlen(str)));
745 }
746
747 void duk_trans_dvalue_send_lstring(duk_trans_dvalue_ctx *ctx, const char *str, size_t len) {
748 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_STRING, str, len));
749 }
750
751 void duk_trans_dvalue_send_buffer(duk_trans_dvalue_ctx *ctx, const char *buf, size_t len) {
752 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, buf, len));
753 }
754
755 void duk_trans_dvalue_send_unused(duk_trans_dvalue_ctx *ctx) {
756 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_UNUSED));
757 }
758
759 void duk_trans_dvalue_send_undefined(duk_trans_dvalue_ctx *ctx) {
760 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_UNDEFINED));
761 }
762
763 void duk_trans_dvalue_send_null(duk_trans_dvalue_ctx *ctx) {
764 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_NULL));
765 }
766
767 void duk_trans_dvalue_send_true(duk_trans_dvalue_ctx *ctx) {
768 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_TRUE));
769 }
770
771 void duk_trans_dvalue_send_false(duk_trans_dvalue_ctx *ctx) {
772 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_FALSE));
773 }
774
775 void duk_trans_dvalue_send_number(duk_trans_dvalue_ctx *ctx, double val) {
776 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_double(DUK_DVALUE_NUMBER, val));
777 }
778
779 void duk_trans_dvalue_send_object(duk_trans_dvalue_ctx *ctx, int classnum, const char *ptr_data, size_t ptr_len) {
780 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int_data(DUK_DVALUE_OBJECT, classnum, ptr_data, ptr_len));
781 }
782
783 void duk_trans_dvalue_send_pointer(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len) {
784 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_POINTER, ptr_data, ptr_len));
785 }
786
787 void duk_trans_dvalue_send_lightfunc(duk_trans_dvalue_ctx *ctx, int lf_flags, const char *ptr_data, size_t ptr_len) {
788 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int_data(DUK_DVALUE_LIGHTFUNC, lf_flags, ptr_data, ptr_len));
789 }
790
791 void duk_trans_dvalue_send_heapptr(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len) {
792 duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_HEAPPTR, ptr_data, ptr_len));
793 }
794
795 void duk_trans_dvalue_send_req_cmd(duk_trans_dvalue_ctx *ctx, int cmd) {
796 duk_trans_dvalue_send_req(ctx);
797 duk_trans_dvalue_send_integer(ctx, cmd);
798 }
799
800 static duk_dvalue *duk__trans_trial_parse_dvalue(duk_trans_dvalue_ctx *ctx) {
801 unsigned char *p;
802 size_t len;
803 unsigned char ib;
804 duk_dvalue *dv;
805 size_t datalen;
806
807 p = ctx->recv_buf.base + ctx->recv_buf.read_offset;
808 len = ctx->recv_buf.write_offset - ctx->recv_buf.read_offset;
809
810 if (len == 0) {
811 return NULL;
812 }
813 ib = p[0];
814
815 #if defined(DEBUG_PRINTS)
816 {
817 size_t i;
818 fprintf(stderr, "%s: parsing dvalue, window:", __func__);
819 for (i = 0; i < 16; i++) {
820 if (i < len) {
821 fprintf(stderr, " %02x", (unsigned int) p[i]);
822 } else {
823 fprintf(stderr, " ??");
824 }
825 }
826 fprintf(stderr, " (length %ld, read_offset %ld, write_offset %ld, alloc_size %ld)\n",
827 (long) len, (long) ctx->recv_buf.read_offset, (long) ctx->recv_buf.write_offset,
828 (long) ctx->recv_buf.alloc_size);
829 fflush(stderr);
830 }
831 #endif
832
833 if (ib <= 0x1fU) {
834 /* 0x00 ... 0x1f */
835 switch (ib) {
836 case 0x00: {
837 ctx->recv_buf.read_offset += 1;
838 dv = duk_dvalue_make_tag(DUK_DVALUE_EOM);
839 if (!dv) { goto alloc_error; }
840 return dv;
841 }
842 case 0x01: {
843 ctx->recv_buf.read_offset += 1;
844 dv = duk_dvalue_make_tag(DUK_DVALUE_REQ);
845 if (!dv) { goto alloc_error; }
846 return dv;
847 }
848 case 0x02: {
849 ctx->recv_buf.read_offset += 1;
850 dv = duk_dvalue_make_tag(DUK_DVALUE_REP);
851 if (!dv) { goto alloc_error; }
852 return dv;
853 }
854 case 0x03: {
855 ctx->recv_buf.read_offset += 1;
856 dv = duk_dvalue_make_tag(DUK_DVALUE_ERR);
857 if (!dv) { goto alloc_error; }
858 return dv;
859 }
860 case 0x04: {
861 ctx->recv_buf.read_offset += 1;
862 dv = duk_dvalue_make_tag(DUK_DVALUE_NFY);
863 if (!dv) { goto alloc_error; }
864 return dv;
865 }
866 case 0x10: {
867 int intval;
868 if (len < 5) { goto partial; }
869 intval = duk__trans_dvalue_parse_i32(ctx, p + 1);
870 ctx->recv_buf.read_offset += 5;
871 dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval);
872 if (!dv) { goto alloc_error; }
873 return dv;
874 }
875 case 0x11: {
876 if (len < 5) { goto partial; }
877 datalen = (size_t) duk__trans_dvalue_parse_u32(ctx, p + 1);
878 if (len < 5 + datalen) { goto partial; }
879 ctx->recv_buf.read_offset += 5 + datalen;
880 dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 5), datalen);
881 if (!dv) { goto alloc_error; }
882 return dv;
883 }
884 case 0x12: {
885 if (len < 3) { goto partial; }
886 datalen = (size_t) duk__trans_dvalue_parse_u16(ctx, p + 1);
887 if (len < 3 + datalen) { goto partial; }
888 ctx->recv_buf.read_offset += 3 + datalen;
889 dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 3), datalen);
890 if (!dv) { goto alloc_error; }
891 return dv;
892 }
893 case 0x13: {
894 if (len < 5) { goto partial; }
895 datalen = (size_t) duk__trans_dvalue_parse_u32(ctx, p + 1);
896 if (len < 5 + datalen) { goto partial; }
897 ctx->recv_buf.read_offset += 5 + datalen;
898 dv = duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, (const char *) (p + 5), datalen);
899 if (!dv) { goto alloc_error; }
900 return dv;
901 }
902 case 0x14: {
903 if (len < 3) { goto partial; }
904 datalen = (size_t) duk__trans_dvalue_parse_u16(ctx, p + 1);
905 if (len < 3 + datalen) { goto partial; }
906 ctx->recv_buf.read_offset += 3 + datalen;
907 dv = duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, (const char *) (p + 3), datalen);
908 if (!dv) { goto alloc_error; }
909 return dv;
910 }
911 case 0x15: {
912 ctx->recv_buf.read_offset += 1;
913 dv = duk_dvalue_make_tag(DUK_DVALUE_UNUSED);
914 if (!dv) { goto alloc_error; }
915 return dv;
916 }
917 case 0x16: {
918 ctx->recv_buf.read_offset += 1;
919 dv = duk_dvalue_make_tag(DUK_DVALUE_UNDEFINED);
920 if (!dv) { goto alloc_error; }
921 return dv;
922 }
923 case 0x17: {
924 ctx->recv_buf.read_offset += 1;
925 dv = duk_dvalue_make_tag(DUK_DVALUE_NULL);
926 if (!dv) { goto alloc_error; }
927 return dv;
928 }
929 case 0x18: {
930 ctx->recv_buf.read_offset += 1;
931 dv = duk_dvalue_make_tag(DUK_DVALUE_TRUE);
932 if (!dv) { goto alloc_error; }
933 return dv;
934 }
935 case 0x19: {
936 ctx->recv_buf.read_offset += 1;
937 dv = duk_dvalue_make_tag(DUK_DVALUE_FALSE);
938 if (!dv) { goto alloc_error; }
939 return dv;
940 }
941 case 0x1a: {
942 double dblval;
943 if (len < 9) { goto partial; }
944 dblval = duk__trans_dvalue_parse_double(ctx, p + 1);
945 ctx->recv_buf.read_offset += 9;
946 dv = duk_dvalue_make_tag_double(DUK_DVALUE_NUMBER, dblval);
947 if (!dv) { goto alloc_error; }
948 return dv;
949 }
950 case 0x1b: {
951 int classnum;
952 if (len < 3) { goto partial; }
953 datalen = (size_t) p[2];
954 if (len < 3 + datalen) { goto partial; }
955 classnum = (int) p[1];
956 ctx->recv_buf.read_offset += 3 + datalen;
957 dv = duk_dvalue_make_tag_int_data(DUK_DVALUE_OBJECT, classnum, (const char *) (p + 3), datalen);
958 if (!dv) { goto alloc_error; }
959 return dv;
960 }
961 case 0x1c: {
962 if (len < 2) { goto partial; }
963 datalen = (size_t) p[1];
964 if (len < 2 + datalen) { goto partial; }
965 ctx->recv_buf.read_offset += 2 + datalen;
966 dv = duk_dvalue_make_tag_data(DUK_DVALUE_POINTER, (const char *) (p + 2), datalen);
967 if (!dv) { goto alloc_error; }
968 return dv;
969 }
970 case 0x1d: {
971 int lf_flags;
972 if (len < 4) { goto partial; }
973 datalen = (size_t) p[3];
974 if (len < 4 + datalen) { goto partial; }
975 lf_flags = (int) duk__trans_dvalue_parse_u16(ctx, p + 1);
976 ctx->recv_buf.read_offset += 4 + datalen;
977 dv = duk_dvalue_make_tag_int_data(DUK_DVALUE_LIGHTFUNC, lf_flags, (const char *) (p + 4), datalen);
978 if (!dv) { goto alloc_error; }
979 return dv;
980 }
981 case 0x1e: {
982 if (len < 2) { goto partial; }
983 datalen = (size_t) p[1];
984 if (len < 2 + datalen) { goto partial; }
985 ctx->recv_buf.read_offset += 2 + datalen;
986 dv = duk_dvalue_make_tag_data(DUK_DVALUE_HEAPPTR, (const char *) (p + 2), datalen);
987 if (!dv) { goto alloc_error; }
988 return dv;
989 }
990 default: {
991 goto format_error;
992 }
993 } /* end switch */
994 } else if (ib <= 0x5fU) {
995 /* 0x20 ... 0x5f */
996 goto format_error;
997 } else if (ib <= 0x7fU) {
998 /* 0x60 ... 0x7f */
999 datalen = (size_t) (ib - 0x60U);
1000 if (len < 1 + datalen) { goto partial; }
1001 ctx->recv_buf.read_offset += 1 + datalen;
1002 dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 1), datalen);
1003 if (!dv) { goto alloc_error; }
1004 return dv;
1005 } else if (ib <= 0xbfU) {
1006 /* 0x80 ... 0xbf */
1007 int intval;
1008 intval = (int) (ib - 0x80U);
1009 ctx->recv_buf.read_offset += 1;
1010 dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval);
1011 if (!dv) { goto alloc_error; }
1012 return dv;
1013 } else {
1014 /* 0xc0 ... 0xff */
1015 int intval;
1016 if (len < 2) { goto partial; }
1017 intval = (((int) (ib - 0xc0U)) << 8) + (int) p[1];
1018 ctx->recv_buf.read_offset += 2;
1019 dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval);
1020 if (!dv) { goto alloc_error; }
1021 return dv;
1022 }
1023
1024 /* never here */
1025
1026 partial:
1027 return NULL;
1028
1029 alloc_error:
1030 #if defined(ERROR_PRINTS)
1031 fprintf(stderr, "%s: internal error, cannot allocate space for dvalue\n", __func__);
1032 fflush(stdout);
1033 #endif
1034 return NULL;
1035
1036 format_error:
1037 #if defined(ERROR_PRINTS)
1038 fprintf(stderr, "%s: internal error, dvalue format error\n", __func__);
1039 fflush(stdout);
1040 #endif
1041 return NULL;
1042 }
1043
1044 static duk_dvalue *duk__trans_trial_parse_handshake(duk_trans_dvalue_ctx *ctx) {
1045 unsigned char *p;
1046 size_t len;
1047 duk_dvalue *dv;
1048 size_t i;
1049
1050 p = ctx->recv_buf.base + ctx->recv_buf.read_offset;
1051 len = ctx->recv_buf.write_offset - ctx->recv_buf.read_offset;
1052
1053 for (i = 0; i < len; i++) {
1054 if (p[i] == 0x0a) {
1055 /* Handshake line is returned as a dvalue for convenience; it's
1056 * not actually a part of the dvalue phase of the protocol.
1057 */
1058 ctx->recv_buf.read_offset += i + 1;
1059 dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) p, i);
1060 if (!dv) { goto alloc_error; }
1061 return dv;
1062 }
1063 }
1064
1065 return NULL;
1066
1067 alloc_error:
1068 #if defined(ERROR_PRINTS)
1069 fprintf(stderr, "%s: internal error, cannot allocate space for handshake line\n", __func__);
1070 fflush(stdout);
1071 #endif
1072 return NULL;
1073 }
1074
1075 static void duk__trans_call_cooperate(duk_trans_dvalue_ctx *ctx, int block) {
1076 if (ctx->cooperate) {
1077 ctx->cooperate(ctx, block);
1078 }
1079 }
1080
1081 static void duk__trans_call_received(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) {
1082 if (ctx->received) {
1083 ctx->received(ctx, dv);
1084 }
1085 }
1086
1087 static void duk__trans_call_handshake(duk_trans_dvalue_ctx *ctx, const char *line) {
1088 if (ctx->handshake) {
1089 ctx->handshake(ctx, line);
1090 }
1091 }
1092
1093 static void duk__trans_call_detached(duk_trans_dvalue_ctx *ctx) {
1094 if (ctx->detached) {
1095 ctx->detached(ctx);
1096 }
1097 }
1098
1099 /*
1100 * Duktape callbacks
1101 */
1102
1103 duk_size_t duk_trans_dvalue_read_cb(void *udata, char *buffer, duk_size_t length) {
1104 duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1105
1106 #if defined(DEBUG_PRINTS)
1107 fprintf(stderr, "%s: %p %p %ld\n", __func__, udata, (void *) buffer, (long) length);
1108 fflush(stderr);
1109 #endif
1110
1111 duk__trans_call_cooperate(ctx, 0);
1112
1113 for (;;) {
1114 size_t avail, now;
1115
1116 avail = (size_t) (ctx->send_buf.write_offset - ctx->send_buf.read_offset);
1117 if (avail == 0) {
1118 /* Must cooperate until user callback provides data. From
1119 * Duktape's perspective we MUST block until data is received.
1120 */
1121 duk__trans_call_cooperate(ctx, 1);
1122 } else {
1123 now = avail;
1124 if (now > length) {
1125 now = length;
1126 }
1127 memcpy((void *) buffer, (const void *) (ctx->send_buf.base + ctx->send_buf.read_offset), now);
1128 duk__trans_buffer_rebase(&ctx->send_buf);
1129 ctx->send_buf.read_offset += now;
1130 return now;
1131 }
1132 }
1133 }
1134
1135 duk_size_t duk_trans_dvalue_write_cb(void *udata, const char *buffer, duk_size_t length) {
1136 duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1137 unsigned char *p;
1138
1139 #if defined(DEBUG_PRINTS)
1140 fprintf(stderr, "%s: %p %p %ld\n", __func__, udata, (void *) buffer, (long) length);
1141 fflush(stderr);
1142 #endif
1143
1144 duk__trans_call_cooperate(ctx, 0);
1145
1146 /* Append data. */
1147 duk__trans_buffer_rebase(&ctx->recv_buf);
1148 p = duk__trans_buffer_ensure(&ctx->recv_buf, length);
1149 memcpy((void *) p, (const void *) buffer, (size_t) length);
1150 ctx->recv_buf.write_offset += length;
1151
1152 /* Trial parse handshake line or dvalue(s). */
1153 if (!ctx->handshake_done) {
1154 duk_dvalue *dv = duk__trans_trial_parse_handshake(ctx);
1155 if (dv) {
1156 /* Handshake line is available for caller for the
1157 * duration of the callback, and must not be freed
1158 * by the caller.
1159 */
1160 duk__trans_call_handshake(ctx, (const char *) dv->buf);
1161 #if defined(DEBUG_PRINTS)
1162 fprintf(stderr, "%s: handshake ok\n", __func__);
1163 fflush(stderr);
1164 #endif
1165 duk_dvalue_free(dv);
1166 ctx->handshake_done = 1;
1167 }
1168 }
1169 if (ctx->handshake_done) {
1170 for (;;) {
1171 duk_dvalue *dv = duk__trans_trial_parse_dvalue(ctx);
1172 if (dv) {
1173 #if defined(DEBUG_PRINTS)
1174 {
1175 char buf[DUK_DVALUE_TOSTRING_BUFLEN];
1176 duk_dvalue_to_string(dv, buf);
1177 fprintf(stderr, "%s: received dvalue: %s\n", __func__, buf);
1178 fflush(stderr);
1179 }
1180 #endif
1181
1182 duk__trans_call_received(ctx, dv);
1183 } else {
1184 break;
1185 }
1186 }
1187 }
1188
1189 duk__trans_call_cooperate(ctx, 0); /* just in case, if dvalues changed something */
1190
1191 return length;
1192 }
1193
1194 duk_size_t duk_trans_dvalue_peek_cb(void *udata) {
1195 duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1196 size_t avail;
1197
1198 #if defined(DEBUG_PRINTS)
1199 fprintf(stderr, "%s: %p\n", __func__, udata);
1200 fflush(stderr);
1201 #endif
1202
1203 duk__trans_call_cooperate(ctx, 0);
1204 avail = (size_t) (ctx->send_buf.write_offset - ctx->send_buf.read_offset);
1205 return (duk_size_t) avail;
1206 }
1207
1208 void duk_trans_dvalue_read_flush_cb(void *udata) {
1209 duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1210
1211 #if defined(DEBUG_PRINTS)
1212 fprintf(stderr, "%s: %p\n", __func__, udata);
1213 fflush(stderr);
1214 #endif
1215
1216 duk__trans_call_cooperate(ctx, 0);
1217 }
1218
1219 void duk_trans_dvalue_write_flush_cb(void *udata) {
1220 duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1221
1222 #if defined(DEBUG_PRINTS)
1223 fprintf(stderr, "%s: %p\n", __func__, udata);
1224 fflush(stderr);
1225 #endif
1226
1227 duk__trans_call_cooperate(ctx, 0);
1228 }
1229
1230 void duk_trans_dvalue_detached_cb(void *udata) {
1231 duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1232
1233 #if defined(DEBUG_PRINTS)
1234 fprintf(stderr, "%s: %p\n", __func__, udata);
1235 fflush(stderr);
1236 #endif
1237
1238 duk__trans_call_detached(ctx);
1239 }