http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/README.rst ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/README.rst b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/README.rst new file mode 100644 index 0000000..5b1b147 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/README.rst @@ -0,0 +1,76 @@ +================== +Eventloop examples +================== + +Overview and usage +================== + +A few examples on how an event loop can be implemented with Duktape, mainly +illlustrating how the Duktape interface works (not how event loops should be +built otherwise). + +To test (Linux only, perhaps other Unix):: + + $ make + $ ./evloop curses-timers.js # run with Ecmascript eventloop + $ ./evloop -c curses-timers.js # run with C eventloop + +Implementation approaches +========================= + +There are several approaches to implementation timers. Here we demonstrate +two main approaches: + +1. Using a C eventloop which calls into Javascript. All the event loop state + like timers, sockets, etc, is held in C structures. + (See ``c_eventloop.c`` and ``c_eventloop.js``.) + +2. Using an Ecmascript eventloop which never returns. All the event loop state + can be managed with Ecmascript code instead of C structures. The Ecmascript + eventloop calls a Duktape/C helper to do the lowest level poll() call. + (See ``ecma_eventloop.js``.) + +Services provided +================= + +The event loop API provided by both examples is the same, and includes: + +* Timers: setTimeout, clearTimeout, setInterval, clearInterval + +* Sockets: simple network sockets + +In addition there are a few synchronous API bindings which are not event loop +related: + +* File I/O + +* Curses, for doing beautiful character graphics + +Limitations +=========== + +This is **not** a production quality event loop. This is on purpose, to +keep the example somewhat simple. Some shortcomings include: + +* A production quality event loop would track its internal state (active + timers and sockets) much more efficiently. In general memory usage and + code footprint can be reduced. + +* Buffer churn caused by allocating a new buffer for every socket read + should be eliminated by reusing buffers where appropriate. Although + churn doesn't increase memory footprint with reference counting, it + is slower than reusing buffers and might increase memory fragmentation. + +* There is no way to suspend reading or writing in the example. Adding + them is straightforward: the poll set needs to be managed dynamically. + +* The example uses poll() while one should use epoll() on Linux, kqueue() + on BSD systems, etc. + +* Timers are not very accurate, e.g. setInterval() does not try to guarantee + a steady schedule. Instead, the next interval is scheduled after the + current callback has finished. This is not the best behavior for some + environments, but avoids bunching callbacks. + +* Error handling is mostly missing. Debug prints don't interact well + with curses.
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/basic-test.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/basic-test.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/basic-test.js new file mode 100644 index 0000000..04b3392 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/basic-test.js @@ -0,0 +1,17 @@ +/* + * A few basic tests + */ + +var count = 0; +var intervalId; + +setTimeout(function (x) { print('timer 1', x); }, 1234, 'foo'); +setTimeout('print("timer 2");', 4321); +setTimeout(function () { print('timer 3'); }, 2345); +intervalId = setInterval(function (x, y) { + print('interval', ++count, x, y); + if (count >= 10) { + clearInterval(intervalId); + } +}, 400, 'foo', 'bar'); + http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.c new file mode 100644 index 0000000..75d768b --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.c @@ -0,0 +1,618 @@ +/* + * C eventloop example. + * + * Timer management is similar to eventloop.js but implemented in C. + * In particular, timer insertion is an O(n) operation; in a real world + * eventloop based on a heap insertion would be O(log N). + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <sys/time.h> +#include <poll.h> + +#include "duktape.h" + +#define MAX_TIMERS 4096 /* this is quite excessive for embedded use, but good for testing */ +#define MIN_DELAY 1.0 +#define MIN_WAIT 1.0 +#define MAX_WAIT 60000.0 +#define MAX_EXPIRYS 10 + +#define MAX_FDS 256 + +typedef struct { + int64_t id; /* numeric ID (returned from e.g. setTimeout); zero if unused */ + double target; /* next target time */ + double delay; /* delay/interval */ + int oneshot; /* oneshot=1 (setTimeout), repeated=0 (setInterval) */ + int removed; /* timer has been requested for removal */ + + /* The callback associated with the timer is held in the "global stash", + * in <stash>.eventTimers[String(id)]. The references must be deleted + * when a timer struct is deleted. + */ +} ev_timer; + +/* Active timers. Dense list, terminates to end of list or first unused timer. + * The list is sorted by 'target', with lowest 'target' (earliest expiry) last + * in the list. When a timer's callback is being called, the timer is moved + * to 'timer_expiring' as it needs special handling should the user callback + * delete that particular timer. + */ +static ev_timer timer_list[MAX_TIMERS]; +static ev_timer timer_expiring; +static int timer_count; /* last timer at timer_count - 1 */ +static int64_t timer_next_id = 1; + +/* Socket poll state. */ +static struct pollfd poll_list[MAX_FDS]; +static int poll_count = 0; + +/* Misc */ +static int exit_requested = 0; + +/* Get Javascript compatible 'now' timestamp (millisecs since 1970). */ +static double get_now(void) { + struct timeval tv; + int rc; + + rc = gettimeofday(&tv, NULL); + if (rc != 0) { + /* Should never happen, so return whatever. */ + return 0.0; + } + return ((double) tv.tv_sec) * 1000.0 + ((double) tv.tv_usec) / 1000.0; +} + +static ev_timer *find_nearest_timer(void) { + /* Last timer expires first (list is always kept sorted). */ + if (timer_count <= 0) { + return NULL; + } + return timer_list + timer_count - 1; +} + +/* Bubble last timer on timer list backwards until it has been moved to + * its proper sorted position (based on 'target' time). + */ +static void bubble_last_timer(void) { + int i; + int n = timer_count; + ev_timer *t; + ev_timer tmp; + + for (i = n - 1; i > 0; i--) { + /* Timer to bubble is at index i, timer to compare to is + * at i-1 (both guaranteed to exist). + */ + t = timer_list + i; + if (t->target <= (t-1)->target) { + /* 't' expires earlier than (or same time as) 't-1', so we're done. */ + break; + } else { + /* 't' expires later than 't-1', so swap them and repeat. */ + memcpy((void *) &tmp, (void *) (t - 1), sizeof(ev_timer)); + memcpy((void *) (t - 1), (void *) t, sizeof(ev_timer)); + memcpy((void *) t, (void *) &tmp, sizeof(ev_timer)); + } + } +} + +static void expire_timers(duk_context *ctx) { + ev_timer *t; + int sanity = MAX_EXPIRYS; + double now; + int rc; + + /* Because a user callback can mutate the timer list (by adding or deleting + * a timer), we expire one timer and then rescan from the end again. There + * is a sanity limit on how many times we do this per expiry round. + */ + + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, "eventTimers"); + + /* [ ... stash eventTimers ] */ + + now = get_now(); + while (sanity-- > 0) { + /* + * If exit has been requested, exit without running further + * callbacks. + */ + + if (exit_requested) { +#if 0 + fprintf(stderr, "exit requested, exiting timer expiry loop\n"); + fflush(stderr); +#endif + break; + } + + /* + * Expired timer(s) still exist? + */ + + if (timer_count <= 0) { + break; + } + t = timer_list + timer_count - 1; + if (t->target > now) { + break; + } + + /* + * Move the timer to 'expiring' for the duration of the callback. + * Mark a one-shot timer deleted, compute a new target for an interval. + */ + + memcpy((void *) &timer_expiring, (void *) t, sizeof(ev_timer)); + memset((void *) t, 0, sizeof(ev_timer)); + timer_count--; + t = &timer_expiring; + + if (t->oneshot) { + t->removed = 1; + } else { + t->target = now + t->delay; /* XXX: or t->target + t->delay? */ + } + + /* + * Call timer callback. The callback can operate on the timer list: + * add new timers, remove timers. The callback can even remove the + * expired timer whose callback we're calling. However, because the + * timer being expired has been moved to 'timer_expiring', we don't + * need to worry about the timer's offset changing on the timer list. + */ + +#if 0 + fprintf(stderr, "calling user callback for timer id %d\n", (int) t->id); + fflush(stderr); +#endif + + duk_push_number(ctx, (double) t->id); + duk_get_prop(ctx, -2); /* -> [ ... stash eventTimers func ] */ + rc = duk_pcall(ctx, 0 /*nargs*/); /* -> [ ... stash eventTimers retval ] */ + if (rc != 0) { +#if 0 + fprintf(stderr, "timer callback failed for timer %d: %s\n", (int) t->id, duk_to_string(ctx, -1)); + fflush(stderr); +#endif + } + duk_pop(ctx); /* ignore errors for now -> [ ... stash eventTimers ] */ + + if (t->removed) { + /* One-shot timer (always removed) or removed by user callback. */ +#if 0 + fprintf(stderr, "deleting callback state for timer %d\n", (int) t->id); + fflush(stderr); +#endif + duk_push_number(ctx, (double) t->id); + duk_del_prop(ctx, -2); + } else { + /* Interval timer, not removed by user callback. Queue back to + * timer list and bubble to its final sorted position. + */ +#if 0 + fprintf(stderr, "queueing timer %d back into active list\n", (int) t->id); + fflush(stderr); +#endif + if (timer_count >= MAX_TIMERS) { + duk_error(ctx, DUK_ERR_RANGE_ERROR, "out of timer slots"); + } + memcpy((void *) (timer_list + timer_count), (void *) t, sizeof(ev_timer)); + timer_count++; + bubble_last_timer(); + } + } + + memset((void *) &timer_expiring, 0, sizeof(ev_timer)); + + duk_pop_2(ctx); /* -> [ ... ] */ +} + +static void compact_poll_list(void) { + int i, j, n; + + /* i = input index + * j = output index (initially same as i) + */ + + n = poll_count; + for (i = 0, j = 0; i < n; i++) { + struct pollfd *pfd = poll_list + i; + if (pfd->fd == 0) { + /* keep output index the same */ +#if 0 + fprintf(stderr, "remove pollfd (index %d): fd=%d, events=%d, revents=%d\n", + i, pfd->fd, pfd->events, pfd->revents), + fflush(stderr); +#endif + + continue; + } +#if 0 + fprintf(stderr, "keep pollfd (index %d -> %d): fd=%d, events=%d, revents=%d\n", + i, j, pfd->fd, pfd->events, pfd->revents), + fflush(stderr); +#endif + if (i != j) { + /* copy only if indices have diverged */ + memcpy((void *) (poll_list + j), (void *) (poll_list + i), sizeof(struct pollfd)); + } + j++; + } + + if (j < poll_count) { + /* zeroize unused entries for sanity */ + memset((void *) (poll_list + j), 0, (poll_count - j) * sizeof(struct pollfd)); + } + + poll_count = j; +} + +int eventloop_run(duk_context *ctx) { + ev_timer *t; + double now; + double diff; + int timeout; + int rc; + int i, n; + int idx_eventloop; + int idx_fd_handler; + + /* The Ecmascript poll handler is passed through EventLoop.fdPollHandler + * which c_eventloop.js sets before we come here. + */ + duk_push_global_object(ctx); + duk_get_prop_string(ctx, -1, "EventLoop"); + duk_get_prop_string(ctx, -1, "fdPollHandler"); /* -> [ global EventLoop fdPollHandler ] */ + idx_fd_handler = duk_get_top_index(ctx); + idx_eventloop = idx_fd_handler - 1; + + for (;;) { + /* + * Expire timers. + */ + + expire_timers(ctx); + + /* + * If exit requested, bail out as fast as possible. + */ + + if (exit_requested) { +#if 0 + fprintf(stderr, "exit requested, exiting event loop\n"); + fflush(stderr); +#endif + break; + } + + /* + * Compact poll list by removing pollfds with fd == 0. + */ + + compact_poll_list(); + + /* + * Determine poll() timeout (as close to poll() as possible as + * the wait is relative). + */ + + now = get_now(); + t = find_nearest_timer(); + if (t) { + diff = t->target - now; + if (diff < MIN_WAIT) { + diff = MIN_WAIT; + } else if (diff > MAX_WAIT) { + diff = MAX_WAIT; + } + timeout = (int) diff; /* clamping ensures that fits */ + } else { + if (poll_count == 0) { +#if 0 + fprintf(stderr, "no timers and no sockets to poll, exiting\n"); + fflush(stderr); +#endif + break; + } + timeout = (int) MAX_WAIT; + } + + /* + * Poll for activity or timeout. + */ + +#if 0 + fprintf(stderr, "going to poll, timeout %d ms, pollfd count %d\n", timeout, poll_count); + fflush(stderr); +#endif + + rc = poll(poll_list, poll_count, timeout); +#if 0 + fprintf(stderr, "poll rc: %d\n", rc); + fflush(stderr); +#endif + if (rc < 0) { + /* error */ + } else if (rc == 0) { + /* timeout */ + } else { + /* 'rc' fds active */ + } + + /* + * Check socket activity, handle all sockets. Handling is offloaded to + * Ecmascript code (fd + revents). + * + * If FDs are removed from the poll list while we're processing callbacks, + * the entries are simply marked unused (fd set to 0) without actually + * removing them from the poll list. This ensures indices are not + * disturbed. The poll list is compacted before next poll(). + */ + + n = (rc == 0 ? 0 : poll_count); /* if timeout, no need to check pollfd */ + for (i = 0; i < n; i++) { + struct pollfd *pfd = poll_list + i; + + if (pfd->fd == 0) { + /* deleted, perhaps by previous callback */ + continue; + } + + if (pfd->revents) { +#if 0 + fprintf(stderr, "fd %d has revents: %d\n", (int) pfd->fd, (int) pfd->revents); + fflush(stderr); +#endif + duk_dup(ctx, idx_fd_handler); + duk_dup(ctx, idx_eventloop); + duk_push_int(ctx, pfd->fd); + duk_push_int(ctx, pfd->revents); + rc = duk_pcall_method(ctx, 2 /*nargs*/); + if (rc) { +#if 0 + fprintf(stderr, "fd callback failed for fd %d: %s\n", (int) pfd->fd, duk_to_string(ctx, -1)); + fflush(stderr); +#endif + } + duk_pop(ctx); + + pfd->revents = 0; + } + + } + } + + duk_pop_n(ctx, 3); + + return 0; +} + +static int create_timer(duk_context *ctx) { + double delay; + int oneshot; + int idx; + int64_t timer_id; + double now; + ev_timer *t; + + now = get_now(); + + /* indexes: + * 0 = function (callback) + * 1 = delay + * 2 = boolean: oneshot + */ + + delay = duk_require_number(ctx, 1); + if (delay < MIN_DELAY) { + delay = MIN_DELAY; + } + oneshot = duk_require_boolean(ctx, 2); + + if (timer_count >= MAX_TIMERS) { + duk_error(ctx, DUK_ERR_RANGE_ERROR, "out of timer slots"); + } + idx = timer_count++; + timer_id = timer_next_id++; + t = timer_list + idx; + + memset((void *) t, 0, sizeof(ev_timer)); + t->id = timer_id; + t->target = now + delay; + t->delay = delay; + t->oneshot = oneshot; + t->removed = 0; + + /* Timer is now at the last position; use swaps to "bubble" it to its + * correct sorted position. + */ + + bubble_last_timer(); + + /* Finally, register the callback to the global stash 'eventTimers' object. */ + + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, "eventTimers"); /* -> [ func delay oneshot stash eventTimers ] */ + duk_push_number(ctx, (double) timer_id); + duk_dup(ctx, 0); + duk_put_prop(ctx, -3); /* eventTimers[timer_id] = callback */ + + /* Return timer id. */ + + duk_push_number(ctx, (double) timer_id); +#if 0 + fprintf(stderr, "created timer id: %d\n", (int) timer_id); + fflush(stderr); +#endif + return 1; +} + +static int delete_timer(duk_context *ctx) { + int i, n; + int64_t timer_id; + ev_timer *t; + int found = 0; + + /* indexes: + * 0 = timer id + */ + + timer_id = (int64_t) duk_require_number(ctx, 0); + + /* + * Unlike insertion, deletion needs a full scan of the timer list + * and an expensive remove. If no match is found, nothing is deleted. + * Caller gets a boolean return code indicating match. + * + * When a timer is being expired and its user callback is running, + * the timer has been moved to 'timer_expiring' and its deletion + * needs special handling: just mark it to-be-deleted and let the + * expiry code remove it. + */ + + t = &timer_expiring; + if (t->id == timer_id) { + t->removed = 1; + duk_push_true(ctx); +#if 0 + fprintf(stderr, "deleted expiring timer id: %d\n", (int) timer_id); + fflush(stderr); +#endif + return 1; + } + + n = timer_count; + for (i = 0; i < n; i++) { + t = timer_list + i; + if (t->id == timer_id) { + found = 1; + + /* Shift elements downwards to keep the timer list dense + * (no need if last element). + */ + if (i < timer_count - 1) { + memmove((void *) t, (void *) (t + 1), (timer_count - i - 1) * sizeof(ev_timer)); + } + + /* Zero last element for clarity. */ + memset((void *) (timer_list + n - 1), 0, sizeof(ev_timer)); + + /* Update timer_count. */ + timer_count--; + + /* The C state is now up-to-date, but we still need to delete + * the timer callback state from the global 'stash'. + */ + + duk_push_global_stash(ctx); + duk_get_prop_string(ctx, -1, "eventTimers"); /* -> [ timer_id stash eventTimers ] */ + duk_push_number(ctx, (double) timer_id); + duk_del_prop(ctx, -2); /* delete eventTimers[timer_id] */ + +#if 0 + fprintf(stderr, "deleted timer id: %d\n", (int) timer_id); + fflush(stderr); +#endif + break; + } + } + +#if 0 + if (!found) { + fprintf(stderr, "trying to delete timer id %d, but not found; ignoring\n", (int) timer_id); + fflush(stderr); + } +#endif + + duk_push_boolean(ctx, found); + return 1; +} + +static int listen_fd(duk_context *ctx) { + int fd = duk_require_int(ctx, 0); + int events = duk_require_int(ctx, 1); + int i, n; + struct pollfd *pfd; + +#if 0 + fprintf(stderr, "listen_fd: fd=%d, events=%d\n", fd, events); + fflush(stderr); +#endif + /* events == 0 means stop listening to the FD */ + + n = poll_count; + for (i = 0; i < n; i++) { + pfd = poll_list + i; + if (pfd->fd == fd) { +#if 0 + fprintf(stderr, "listen_fd: fd found at index %d\n", i); + fflush(stderr); +#endif + if (events == 0) { + /* mark to-be-deleted, cleaned up by next poll */ + pfd->fd = 0; + } else { + pfd->events = events; + } + return 0; + } + } + + /* not found, append to list */ +#if 0 + fprintf(stderr, "listen_fd: fd not found on list, add new entry\n"); + fflush(stderr); +#endif + + if (poll_count >= MAX_FDS) { + duk_error(ctx, DUK_ERR_ERROR, "out of fd slots"); + } + + pfd = poll_list + poll_count; + pfd->fd = fd; + pfd->events = events; + pfd->revents = 0; + poll_count++; + + return 0; +} + +static int request_exit(duk_context *ctx) { + (void) ctx; + exit_requested = 1; + return 0; +} + +static duk_function_list_entry eventloop_funcs[] = { + { "createTimer", create_timer, 3 }, + { "deleteTimer", delete_timer, 1 }, + { "listenFd", listen_fd, 2 }, + { "requestExit", request_exit, 0 }, + { NULL, NULL, 0 } +}; + +void eventloop_register(duk_context *ctx) { + memset((void *) timer_list, 0, MAX_TIMERS * sizeof(ev_timer)); + memset((void *) &timer_expiring, 0, sizeof(ev_timer)); + memset((void *) poll_list, 0, MAX_FDS * sizeof(struct pollfd)); + + /* Set global 'EventLoop'. */ + duk_push_global_object(ctx); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, eventloop_funcs); + duk_put_prop_string(ctx, -2, "EventLoop"); + duk_pop(ctx); + + /* Initialize global stash 'eventTimers'. */ + duk_push_global_stash(ctx); + duk_push_object(ctx); + duk_put_prop_string(ctx, -2, "eventTimers"); + duk_pop(ctx); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.js new file mode 100644 index 0000000..b9e2d63 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/c_eventloop.js @@ -0,0 +1,179 @@ +/* + * C eventloop example (c_eventloop.c). + * + * Ecmascript code to initialize the exposed API (setTimeout() etc) when + * using the C eventloop. + * + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Timers + */ + +/* + * Timer API + */ + +function setTimeout(func, delay) { + var cb_func; + var bind_args; + var timer_id; + + if (typeof delay !== 'number') { + throw new TypeError('delay is not a number'); + } + + if (typeof func === 'string') { + // Legacy case: callback is a string. + cb_func = eval.bind(this, func); + } else if (typeof func !== 'function') { + throw new TypeError('callback is not a function/string'); + } else if (arguments.length > 2) { + // Special case: callback arguments are provided. + bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] + bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] + cb_func = func.bind.apply(func, bind_args); + } else { + // Normal case: callback given as a function without arguments. + cb_func = func; + } + + timer_id = EventLoop.createTimer(cb_func, delay, true /*oneshot*/); + + return timer_id; +} + +function clearTimeout(timer_id) { + if (typeof timer_id !== 'number') { + throw new TypeError('timer ID is not a number'); + } + var success = EventLoop.deleteTimer(timer_id); /* retval ignored */ +} + +function setInterval(func, delay) { + var cb_func; + var bind_args; + var timer_id; + + if (typeof delay !== 'number') { + throw new TypeError('delay is not a number'); + } + + if (typeof func === 'string') { + // Legacy case: callback is a string. + cb_func = eval.bind(this, func); + } else if (typeof func !== 'function') { + throw new TypeError('callback is not a function/string'); + } else if (arguments.length > 2) { + // Special case: callback arguments are provided. + bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] + bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] + cb_func = func.bind.apply(func, bind_args); + } else { + // Normal case: callback given as a function without arguments. + cb_func = func; + } + + timer_id = EventLoop.createTimer(cb_func, delay, false /*oneshot*/); + + return timer_id; +} + +function clearInterval(timer_id) { + if (typeof timer_id !== 'number') { + throw new TypeError('timer ID is not a number'); + } + EventLoop.deleteTimer(timer_id); +} + +function requestEventLoopExit() { + EventLoop.requestExit(); +} + +/* + * Socket handling + * + * Ideally this would be implemented more in C than here for more speed + * and smaller footprint: C code would directly maintain the callback state + * and such. + * + * Also for more optimal I/O, the buffer churn caused by allocating and + * freeing a lot of buffer values could be eliminated by reusing buffers. + * Socket reads would then go into a pre-allocated buffer, for instance. + */ + +EventLoop.socketListening = {}; +EventLoop.socketReading = {}; +EventLoop.socketConnecting = {}; + +EventLoop.fdPollHandler = function(fd, revents) { + var data; + var cb; + var rc; + var acc_res; + + //print('activity on fd', fd, 'revents', revents); + + if (revents & Poll.POLLIN) { + cb = this.socketReading[fd]; + if (cb) { + data = Socket.read(fd); // no size control now + //print('READ', Duktape.enc('jx', data)); + if (data.length === 0) { + this.close(fd); + return; + } + cb(fd, data); + } else { + cb = this.socketListening[fd]; + if (cb) { + acc_res = Socket.accept(fd); + //print('ACCEPT:', Duktape.enc('jx', acc_res)); + cb(acc_res.fd, acc_res.addr, acc_res.port); + } else { + //print('UNKNOWN'); + } + } + } + + if (revents & Poll.POLLOUT) { + // Connected + cb = this.socketConnecting[fd]; + if (cb) { + delete this.socketConnecting[fd]; + cb(fd); + } + } + + if ((revents & ~(Poll.POLLIN | Poll.POLLOUT)) !== 0) { + //print('unexpected revents, close fd'); + this.close(fd); + } +} + +EventLoop.server = function(address, port, cb_accepted) { + var fd = Socket.createServerSocket(address, port); + this.socketListening[fd] = cb_accepted; + this.listenFd(fd, Poll.POLLIN); +} + +EventLoop.connect = function(address, port, cb_connected) { + var fd = Socket.connect(address, port); + this.socketConnecting[fd] = cb_connected; + this.listenFd(fd, Poll.POLLOUT); +} + +EventLoop.close = function(fd) { + EventLoop.listenFd(fd, 0); + delete this.socketListening[fd]; + delete this.socketReading[fd]; + delete this.socketConnecting[fd]; + Socket.close(fd); +} + +EventLoop.setReader = function(fd, cb_read) { + this.socketReading[fd] = cb_read; + this.listenFd(fd, Poll.POLLIN); +} + +EventLoop.write = function(fd, data) { + // This simple example doesn't have support for write blocking / draining + var rc = Socket.write(fd, Duktape.Buffer(data)); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/client-socket-test.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/client-socket-test.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/client-socket-test.js new file mode 100644 index 0000000..ff87784 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/client-socket-test.js @@ -0,0 +1,24 @@ + +var HOST = 'localhost'; +var PORT = 80; +var EXIT_TIMEOUT = 300e3; + +print('automatic exit after ' + (EXIT_TIMEOUT / 1e3) + ' seconds'); +setTimeout(function () { + print('exit timer'); + EventLoop.requestExit(); +}, EXIT_TIMEOUT); + +EventLoop.connect(HOST, PORT, function (fd) { + print('connected to ' + HOST + ':' + PORT + ', fd', fd); + EventLoop.setReader(fd, function (fd, data) { + print('read from fd', fd); + print(data); + EventLoop.close(fd); + }); + EventLoop.write(fd, "GET / HTTP/1.1\r\n" + + "Host: " + HOST + "\r\n" + + "User-Agent: client-socket-test.js\r\n" + + "\r\n"); +}); + http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/curses-timers.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/curses-timers.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/curses-timers.js new file mode 100644 index 0000000..4508665 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/curses-timers.js @@ -0,0 +1,79 @@ +/* + * Test using timers and intervals with curses. + */ + +if (typeof Ncurses !== 'object') { + throw new Error('Ncurses required'); +} + +function fillScreen(ch) { + var size, w, h; + var i, j; + + size = Ncurses.getmaxyx(); + h = size[0]; + w = size[1]; + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) { + Ncurses.mvprintw(i, j, ch); + } + } + Ncurses.refresh(); +} + +function main() { + var i, j; + var counters = []; + var size, w, h; + + Ncurses.initscr(); + size = Ncurses.getmaxyx(); + h = size[0]; + w = size[1]; + + fillScreen('.'); + + setInterval(function () { + Ncurses.mvprintw(1, 4, new Date().toISOString()); + Ncurses.refresh(); + }, 1000); + + function addCounter(row, index, interval) { + counters[index] = 0; + setInterval(function () { + counters[index]++; + Ncurses.mvprintw(row, 4, '' + Date.now() + ' ' + counters[index]); + Ncurses.refresh(); + }, interval); + } + + function addRandomChar(row, col, interval) { + setTimeout(function () { + Ncurses.mvprintw(row, col, String.fromCharCode(Math.random() * 64 + 0x20)); + Ncurses.refresh(); + }, interval); + } + + for (i = 0; i < h - 5; i++) { + addCounter(3 + i, i, 363 * i + 400); + } + + /* Here the inserts take a lot of time because the underlying timer manager + * data structure has O(n) insertion performance. + */ + for (i = 0; i < h - 5; i++) { + for (j = 0; j < w - 50; j++) { + // Math.exp(0)...Math.exp(8) is an uneven distribution between 1...~2980. + addRandomChar(3 + i, 28 + j, 58000 - Math.exp(Math.random() * 8) * 20); + } + } + + setTimeout(function () { + Ncurses.endwin(); + Ncurses.delscreen(); + requestEventLoopExit(); + }, 120e3); +} + +main(); http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ecma_eventloop.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ecma_eventloop.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ecma_eventloop.js new file mode 100644 index 0000000..bad4e4d --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ecma_eventloop.js @@ -0,0 +1,466 @@ +/* + * Pure Ecmascript eventloop example. + * + * Timer state handling is inefficient in this trivial example. Timers are + * kept in an array sorted by their expiry time which works well for expiring + * timers, but has O(n) insertion performance. A better implementation would + * use a heap or some other efficient structure for managing timers so that + * all operations (insert, remove, get nearest timer) have good performance. + * + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Timers + */ + +/* + * Event loop + * + * Timers are sorted by 'target' property which indicates expiry time of + * the timer. The timer expiring next is last in the array, so that + * removals happen at the end, and inserts for timers expiring in the + * near future displace as few elements in the array as possible. + */ + +EventLoop = { + // timers + timers: [], // active timers, sorted (nearest expiry last) + expiring: null, // set to timer being expired (needs special handling in clearTimeout/clearInterval) + nextTimerId: 1, + minimumDelay: 1, + minimumWait: 1, + maximumWait: 60000, + maxExpirys: 10, + + // sockets + socketListening: {}, // fd -> callback + socketReading: {}, // fd -> callback + socketConnecting: {}, // fd -> callback + + // misc + exitRequested: false +}; + +EventLoop.dumpState = function() { + print('TIMER STATE:'); + this.timers.forEach(function(t) { + print(' ' + Duktape.enc('jx', t)); + }); + if (this.expiring) { + print(' EXPIRING: ' + Duktape.enc('jx', this.expiring)); + } +} + +// Get timer with lowest expiry time. Since the active timers list is +// sorted, it's always the last timer. +EventLoop.getEarliestTimer = function() { + var timers = this.timers; + n = timers.length; + return (n > 0 ? timers[n - 1] : null); +} + +EventLoop.getEarliestWait = function() { + var t = this.getEarliestTimer(); + return (t ? t.target - Date.now() : null); +} + +EventLoop.insertTimer = function(timer) { + var timers = this.timers; + var i, n, t; + + /* + * Find 'i' such that we want to insert *after* timers[i] at index i+1. + * If no such timer, for-loop terminates with i-1, and we insert at -1+1=0. + */ + + n = timers.length; + for (i = n - 1; i >= 0; i--) { + t = timers[i]; + if (timer.target <= t.target) { + // insert after 't', to index i+1 + break; + } + } + + timers.splice(i + 1 /*start*/, 0 /*deleteCount*/, timer); +} + +// Remove timer/interval with a timer ID. The timer/interval can reside +// either on the active list or it may be an expired timer (this.expiring) +// whose user callback we're running when this function gets called. +EventLoop.removeTimerById = function(timer_id) { + var timers = this.timers; + var i, n, t; + + t = this.expiring; + if (t) { + if (t.id === timer_id) { + // Timer has expired and we're processing its callback. User + // callback has requested timer deletion. Mark removed, so + // that the timer is not reinserted back into the active list. + // This is actually a common case because an interval may very + // well cancel itself. + t.removed = true; + return; + } + } + + n = timers.length; + for (i = 0; i < n; i++) { + t = timers[i]; + if (t.id === timer_id) { + // Timer on active list: mark removed (not really necessary, but + // nice for dumping), and remove from active list. + t.removed = true; + this.timers.splice(i /*start*/, 1 /*deleteCount*/); + return; + } + } + + // no such ID, ignore +} + +EventLoop.processTimers = function() { + var now = Date.now(); + var timers = this.timers; + var sanity = this.maxExpirys; + var n, t; + + /* + * Here we must be careful with mutations: user callback may add and + * delete an arbitrary number of timers. + * + * Current solution is simple: check whether the timer at the end of + * the list has expired. If not, we're done. If it has expired, + * remove it from the active list, record it in this.expiring, and call + * the user callback. If user code deletes the this.expiring timer, + * there is special handling which just marks the timer deleted so + * it won't get inserted back into the active list. + * + * This process is repeated at most maxExpirys times to ensure we don't + * get stuck forever; user code could in principle add more and more + * already expired timers. + */ + + while (sanity-- > 0) { + // If exit requested, don't call any more callbacks. This allows + // a callback to do cleanups and request exit, and can be sure that + // no more callbacks are processed. + + if (this.exitRequested) { + //print('exit requested, exit'); + break; + } + + // Timers to expire? + + n = timers.length; + if (n <= 0) { + break; + } + t = timers[n - 1]; + if (now <= t.target) { + // Timer has not expired, and no other timer could have expired + // either because the list is sorted. + break; + } + timers.pop(); + + // Remove the timer from the active list and process it. The user + // callback may add new timers which is not a problem. The callback + // may also delete timers which is not a problem unless the timer + // being deleted is the timer whose callback we're running; this is + // why the timer is recorded in this.expiring so that clearTimeout() + // and clearInterval() can detect this situation. + + if (t.oneshot) { + t.removed = true; // flag for removal + } else { + t.target = now + t.delay; + } + this.expiring = t; + try { + t.cb(); + } catch (e) { + print('timer callback failed, ignored: ' + e); + } + this.expiring = null; + + // If the timer was one-shot, it's marked 'removed'. If the user callback + // requested deletion for the timer, it's also marked 'removed'. If the + // timer is an interval (and is not marked removed), insert it back into + // the timer list. + + if (!t.removed) { + // Reinsert interval timer to correct sorted position. The timer + // must be an interval timer because one-shot timers are marked + // 'removed' above. + this.insertTimer(t); + } + } +} + +EventLoop.run = function() { + var wait; + var POLLIN = Poll.POLLIN; + var POLLOUT = Poll.POLLOUT; + var poll_set; + var poll_count; + var fd; + var t, rev; + var rc; + var acc_res; + + for (;;) { + /* + * Process expired timers. + */ + + this.processTimers(); + //this.dumpState(); + + /* + * Exit check (may be requested by a user callback) + */ + + if (this.exitRequested) { + //print('exit requested, exit'); + break; + } + + /* + * Create poll socket list. This is a very naive approach. + * On Linux, one could use e.g. epoll() and manage socket lists + * incrementally. + */ + + poll_set = {}; + poll_count = 0; + for (fd in this.socketListening) { + poll_set[fd] = { events: POLLIN, revents: 0 }; + poll_count++; + } + for (fd in this.socketReading) { + poll_set[fd] = { events: POLLIN, revents: 0 }; + poll_count++; + } + for (fd in this.socketConnecting) { + poll_set[fd] = { events: POLLOUT, revents: 0 }; + poll_count++; + } + //print(new Date(), 'poll_set IN:', Duktape.enc('jx', poll_set)); + + /* + * Wait timeout for timer closest to expiry. Since the poll + * timeout is relative, get this as close to poll() as possible. + */ + + wait = this.getEarliestWait(); + if (wait === null) { + if (poll_count === 0) { + print('no active timers and no sockets to poll, exit'); + break; + } else { + wait = this.maximumWait; + } + } else { + wait = Math.min(this.maximumWait, Math.max(this.minimumWait, wait)); + } + + /* + * Do the actual poll. + */ + + try { + Poll.poll(poll_set, wait); + } catch (e) { + // Eat errors silently. When resizing curses window an EINTR + // happens now. + } + + /* + * Process all sockets so that nothing is left unhandled for the + * next round. + */ + + //print(new Date(), 'poll_set OUT:', Duktape.enc('jx', poll_set)); + for (fd in poll_set) { + t = poll_set[fd]; + rev = t.revents; + + if (rev & POLLIN) { + cb = this.socketReading[fd]; + if (cb) { + data = Socket.read(fd); // no size control now + //print('READ', Duktape.enc('jx', data)); + if (data.length === 0) { + //print('zero read for fd ' + fd + ', closing forcibly'); + rc = Socket.close(fd); // ignore result + delete this.socketListening[fd]; + delete this.socketReading[fd]; + } else { + cb(fd, data); + } + } else { + cb = this.socketListening[fd]; + if (cb) { + acc_res = Socket.accept(fd); + //print('ACCEPT:', Duktape.enc('jx', acc_res)); + cb(acc_res.fd, acc_res.addr, acc_res.port); + } else { + //print('UNKNOWN'); + } + } + } + + if (rev & POLLOUT) { + cb = this.socketConnecting[fd]; + if (cb) { + delete this.socketConnecting[fd]; + cb(fd); + } else { + //print('UNKNOWN POLLOUT'); + } + } + + if ((rev & ~(POLLIN | POLLOUT)) !== 0) { + //print('revents ' + t.revents + ' for fd ' + fd + ', closing forcibly'); + rc = Socket.close(fd); // ignore result + delete this.socketListening[fd]; + delete this.socketReading[fd]; + } + } + } +} + +EventLoop.requestExit = function() { + this.exitRequested = true; +} + +EventLoop.server = function(address, port, cb_accepted) { + var fd = Socket.createServerSocket(address, port); + this.socketListening[fd] = cb_accepted; +} + +EventLoop.connect = function(address, port, cb_connected) { + var fd = Socket.connect(address, port); + this.socketConnecting[fd] = cb_connected; +} + +EventLoop.close = function(fd) { + delete this.socketReading[fd]; + delete this.socketListening[fd]; +} + +EventLoop.setReader = function(fd, cb_read) { + this.socketReading[fd] = cb_read; +} + +EventLoop.write = function(fd, data) { + // This simple example doesn't have support for write blocking / draining + var rc = Socket.write(fd, Duktape.Buffer(data)); +} + +/* + * Timer API + * + * These interface with the singleton EventLoop. + */ + +function setTimeout(func, delay) { + var cb_func; + var bind_args; + var timer_id; + var evloop = EventLoop; + + if (typeof delay !== 'number') { + throw new TypeError('delay is not a number'); + } + delay = Math.max(evloop.minimumDelay, delay); + + if (typeof func === 'string') { + // Legacy case: callback is a string. + cb_func = eval.bind(this, func); + } else if (typeof func !== 'function') { + throw new TypeError('callback is not a function/string'); + } else if (arguments.length > 2) { + // Special case: callback arguments are provided. + bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] + bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] + cb_func = func.bind.apply(func, bind_args); + } else { + // Normal case: callback given as a function without arguments. + cb_func = func; + } + + timer_id = evloop.nextTimerId++; + + evloop.insertTimer({ + id: timer_id, + oneshot: true, + cb: cb_func, + delay: delay, + target: Date.now() + delay + }); + + return timer_id; +} + +function clearTimeout(timer_id) { + var evloop = EventLoop; + + if (typeof timer_id !== 'number') { + throw new TypeError('timer ID is not a number'); + } + evloop.removeTimerById(timer_id); +} + +function setInterval(func, delay) { + var cb_func; + var bind_args; + var timer_id; + var evloop = EventLoop; + + if (typeof delay !== 'number') { + throw new TypeError('delay is not a number'); + } + delay = Math.max(evloop.minimumDelay, delay); + + if (typeof func === 'string') { + // Legacy case: callback is a string. + cb_func = eval.bind(this, func); + } else if (typeof func !== 'function') { + throw new TypeError('callback is not a function/string'); + } else if (arguments.length > 2) { + // Special case: callback arguments are provided. + bind_args = Array.prototype.slice.call(arguments, 2); // [ arg1, arg2, ... ] + bind_args.unshift(this); // [ global(this), arg1, arg2, ... ] + cb_func = func.bind.apply(func, bind_args); + } else { + // Normal case: callback given as a function without arguments. + cb_func = func; + } + + timer_id = evloop.nextTimerId++; + + evloop.insertTimer({ + id: timer_id, + oneshot: false, + cb: cb_func, + delay: delay, + target: Date.now() + delay + }); + + return timer_id; +} + +function clearInterval(timer_id) { + var evloop = EventLoop; + + if (typeof timer_id !== 'number') { + throw new TypeError('timer ID is not a number'); + } + evloop.removeTimerById(timer_id); +} + +/* custom call */ +function requestEventLoopExit() { + EventLoop.requestExit(); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/fileio.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/fileio.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/fileio.c new file mode 100644 index 0000000..df94cd4 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/fileio.c @@ -0,0 +1,69 @@ +/* + * File I/O binding example. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "duktape.h" + +static int fileio_readfile(duk_context *ctx) { + const char *filename = duk_to_string(ctx, 0); + FILE *f = NULL; + long len; + void *buf; + size_t got; + + if (!filename) { + goto error; + } + + f = fopen(filename, "rb"); + if (!f) { + goto error; + } + + if (fseek(f, 0, SEEK_END) != 0) { + goto error; + } + + len = ftell(f); + + if (fseek(f, 0, SEEK_SET) != 0) { + goto error; + } + + buf = duk_push_fixed_buffer(ctx, (size_t) len); + + got = fread(buf, 1, len, f); + if (got != (size_t) len) { + goto error; + } + + fclose(f); + f = NULL; + + return 1; + + error: + if (f) { + fclose(f); + } + + return DUK_RET_ERROR; +} + +static duk_function_list_entry fileio_funcs[] = { + { "readfile", fileio_readfile, 1 }, + { NULL, NULL, 0 } +}; + +void fileio_register(duk_context *ctx) { + /* Set global 'FileIo'. */ + duk_push_global_object(ctx); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, fileio_funcs); + duk_put_prop_string(ctx, -2, "FileIo"); + duk_pop(ctx); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/main.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/main.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/main.c new file mode 100644 index 0000000..7627921 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/main.c @@ -0,0 +1,256 @@ +/* + * Main for evloop command line tool. + * + * Runs a given script from file or stdin inside an eventloop. The + * script can then access setTimeout() etc. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifndef NO_SIGNAL +#include <signal.h> +#endif + +#include "duktape.h" + +extern void poll_register(duk_context *ctx); +extern void ncurses_register(duk_context *ctx); +extern void socket_register(duk_context *ctx); +extern void fileio_register(duk_context *ctx); +extern void eventloop_register(duk_context *ctx); +extern int eventloop_run(duk_context *ctx); /* Duktape/C function, safe called */ + +static int c_evloop = 0; + +#ifndef NO_SIGNAL +static void my_sighandler(int x) { + fprintf(stderr, "Got signal %d\n", x); + fflush(stderr); +} +static void set_sigint_handler(void) { + (void) signal(SIGINT, my_sighandler); +} +#endif /* NO_SIGNAL */ + +/* Print error to stderr and pop error. */ +static void print_error(duk_context *ctx, FILE *f) { + if (duk_is_object(ctx, -1) && duk_has_prop_string(ctx, -1, "stack")) { + /* XXX: print error objects specially */ + /* XXX: pcall the string coercion */ + duk_get_prop_string(ctx, -1, "stack"); + if (duk_is_string(ctx, -1)) { + fprintf(f, "%s\n", duk_get_string(ctx, -1)); + fflush(f); + duk_pop_2(ctx); + return; + } else { + duk_pop(ctx); + } + } + duk_to_string(ctx, -1); + fprintf(f, "%s\n", duk_get_string(ctx, -1)); + fflush(f); + duk_pop(ctx); +} + +int wrapped_compile_execute(duk_context *ctx) { + int comp_flags = 0; + int rc; + + /* Compile input and place it into global _USERCODE */ + duk_compile(ctx, comp_flags); + duk_push_global_object(ctx); + duk_insert(ctx, -2); /* [ ... global func ] */ + duk_put_prop_string(ctx, -2, "_USERCODE"); + duk_pop(ctx); +#if 0 + printf("compiled usercode\n"); +#endif + + /* Start a zero timer which will call _USERCODE from within + * the event loop. + */ + fprintf(stderr, "set _USERCODE timer\n"); + fflush(stderr); + duk_eval_string(ctx, "setTimeout(function() { _USERCODE(); }, 0);"); + duk_pop(ctx); + + /* Finally, launch eventloop. This call only returns after the + * eventloop terminates. + */ + if (c_evloop) { + fprintf(stderr, "calling eventloop_run()\n"); + fflush(stderr); + rc = duk_safe_call(ctx, eventloop_run, 0 /*nargs*/, 1 /*nrets*/); + if (rc != 0) { + fprintf(stderr, "eventloop_run() failed: %s\n", duk_to_string(ctx, -1)); + fflush(stderr); + } + duk_pop(ctx); + } else { + fprintf(stderr, "calling EventLoop.run()\n"); + fflush(stderr); + duk_eval_string(ctx, "EventLoop.run();"); + duk_pop(ctx); + } + + return 0; +} + +int handle_fh(duk_context *ctx, FILE *f, const char *filename) { + char *buf = NULL; + int len; + int got; + int rc; + int retval = -1; + + if (fseek(f, 0, SEEK_END) < 0) { + goto error; + } + len = (int) ftell(f); + if (fseek(f, 0, SEEK_SET) < 0) { + goto error; + } + buf = (char *) malloc(len); + if (!buf) { + goto error; + } + + got = fread((void *) buf, (size_t) 1, (size_t) len, f); + + duk_push_lstring(ctx, buf, got); + duk_push_string(ctx, filename); + + free(buf); + buf = NULL; + + rc = duk_safe_call(ctx, wrapped_compile_execute, 2 /*nargs*/, 1 /*nret*/); + if (rc != DUK_EXEC_SUCCESS) { + print_error(ctx, stderr); + goto error; + } else { + duk_pop(ctx); + retval = 0; + } + /* fall thru */ + + error: + if (buf) { + free(buf); + } + return retval; +} + +int handle_file(duk_context *ctx, const char *filename) { + FILE *f = NULL; + int retval; + + f = fopen(filename, "rb"); + if (!f) { + fprintf(stderr, "failed to open source file: %s\n", filename); + fflush(stderr); + goto error; + } + + retval = handle_fh(ctx, f, filename); + + fclose(f); + return retval; + + error: + return -1; +} + +int handle_stdin(duk_context *ctx) { + int retval; + + retval = handle_fh(ctx, stdin, "stdin"); + + return retval; +} + +int main(int argc, char *argv[]) { + duk_context *ctx = NULL; + int retval = 0; + const char *filename = NULL; + int i; + +#ifndef NO_SIGNAL + set_sigint_handler(); + + /* This is useful at the global level; libraries should avoid SIGPIPE though */ + /*signal(SIGPIPE, SIG_IGN);*/ +#endif + + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + if (!arg) { + goto usage; + } + if (strcmp(arg, "-c") == 0) { + c_evloop = 1; + } else if (strlen(arg) > 1 && arg[0] == '-') { + goto usage; + } else { + if (filename) { + goto usage; + } + filename = arg; + } + } + if (!filename) { + goto usage; + } + + ctx = duk_create_heap_default(); + + poll_register(ctx); + ncurses_register(ctx); + socket_register(ctx); + fileio_register(ctx); + + if (c_evloop) { + fprintf(stderr, "Using C based eventloop (omit -c to use Ecmascript based eventloop)\n"); + fflush(stderr); + + eventloop_register(ctx); + duk_eval_file(ctx, "c_eventloop.js"); + } else { + fprintf(stderr, "Using Ecmascript based eventloop (give -c to use C based eventloop)\n"); + fflush(stderr); + + duk_eval_file(ctx, "ecma_eventloop.js"); + } + + fprintf(stderr, "Executing code from: '%s'\n", filename); + fflush(stderr); + + if (strcmp(filename, "-") == 0) { + if (handle_stdin(ctx) != 0) { + retval = 1; + goto cleanup; + } + } else { + if (handle_file(ctx, filename) != 0) { + retval = 1; + goto cleanup; + } + } + + cleanup: + if (ctx) { + duk_destroy_heap(ctx); + } + + return retval; + + usage: + fprintf(stderr, "Usage: evloop [-c] <filename>\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Uses an Ecmascript based eventloop (ecma_eventloop.js) by default.\n"); + fprintf(stderr, "If -c option given, uses a C based eventloop (c_eventloop.{c,js}).\n"); + fprintf(stderr, "If <filename> is '-', the entire STDIN executed.\n"); + fflush(stderr); + exit(1); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ncurses.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ncurses.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ncurses.c new file mode 100644 index 0000000..7734fcc --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/ncurses.c @@ -0,0 +1,105 @@ +/* + * Ncurses bindings example. + * + * VALGRIND NOTE: when you use ncurses, there seems to be no way to get a + * clean valgrind run. Even if ncurses state is properly shut down, there + * will still be some residual leaks. + * + * Debian: install libncurses5-dev + */ + +#include <curses.h> +#include "duktape.h" + +static int ncurses_initscr(duk_context *ctx) { + WINDOW *win; + + win = initscr(); + duk_push_pointer(ctx, (void *) win); + return 1; +} + +static int ncurses_endwin(duk_context *ctx) { + int rc; + + rc = endwin(); + duk_push_int(ctx, rc); + return 1; +} + +static int ncurses_delscreen(duk_context *ctx) { + /* XXX: no screen management now */ + (void) ctx; + return 0; +} + +static int ncurses_getmaxyx(duk_context *ctx) { + int row, col; + + getmaxyx(stdscr, row, col); + + duk_push_array(ctx); + duk_push_int(ctx, row); + duk_put_prop_index(ctx, -2, 0); + duk_push_int(ctx, col); + duk_put_prop_index(ctx, -2, 1); + return 1; +} + +static int ncurses_printw(duk_context *ctx) { + int rc; + const char *str; + + str = duk_to_string(ctx, 0); + rc = printw("%s", str); + duk_push_int(ctx, rc); + return 1; +} + +static int ncurses_mvprintw(duk_context *ctx) { + int y = duk_to_int(ctx, 0); + int x = duk_to_int(ctx, 1); + const char *str = duk_to_string(ctx, 2); + int rc; + + rc = mvprintw(y, x, "%s", str); + duk_push_int(ctx, rc); + return 1; +} + +static int ncurses_refresh(duk_context *ctx) { + int rc; + + rc = refresh(); + duk_push_int(ctx, rc); + return 1; +} + +static int ncurses_getch(duk_context *ctx) { + int rc; + + rc = getch(); + duk_push_int(ctx, rc); + return 1; +} + +static duk_function_list_entry ncurses_funcs[] = { + { "initscr", ncurses_initscr, 0 }, + { "endwin", ncurses_endwin, 0 }, + { "delscreen", ncurses_delscreen, 0 }, + { "getmaxyx", ncurses_getmaxyx, 0 }, + { "printw", ncurses_printw, 1 }, + { "mvprintw", ncurses_mvprintw, 3 }, + { "refresh", ncurses_refresh, 0 }, + { "getch", ncurses_getch, 0 }, + { NULL, NULL, 0 } +}; + +void ncurses_register(duk_context *ctx) { + /* Set global 'Ncurses'. */ + duk_push_global_object(ctx); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, ncurses_funcs); + duk_put_prop_string(ctx, -2, "Ncurses"); + duk_pop(ctx); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/poll.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/poll.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/poll.c new file mode 100644 index 0000000..c78745d --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/poll.c @@ -0,0 +1,111 @@ +/* + * C wrapper for poll(). + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <poll.h> +#include <time.h> + +#include "duktape.h" + +static int poll_poll(duk_context *ctx) { + int timeout = duk_to_int(ctx, 1); + int i, n, nchanged; + int fd, rc; + struct pollfd fds[20]; + struct timespec ts; + + memset(fds, 0, sizeof(fds)); + + n = 0; + duk_enum(ctx, 0, 0 /*enum_flags*/); + while (duk_next(ctx, -1, 0)) { + if ((size_t) n >= sizeof(fds) / sizeof(struct pollfd)) { + return -1; + } + + /* [... enum key] */ + duk_dup_top(ctx); /* -> [... enum key key] */ + duk_get_prop(ctx, 0); /* -> [... enum key val] */ + fd = duk_to_int(ctx, -2); + + duk_push_string(ctx, "events"); + duk_get_prop(ctx, -2); /* -> [... enum key val events] */ + + fds[n].fd = fd; + fds[n].events = duk_to_int(ctx, -1); + fds[n].revents = 0; + + duk_pop_n(ctx, 3); /* -> [... enum] */ + + n++; + } + /* leave enum on stack */ + + memset(&ts, 0, sizeof(ts)); + ts.tv_nsec = (timeout % 1000) * 1000000; + ts.tv_sec = timeout / 1000; + + /*rc = ppoll(fds, n, &ts, NULL);*/ + rc = poll(fds, n, timeout); + if (rc < 0) { + duk_error(ctx, DUK_ERR_ERROR, "%s (errno=%d)", strerror(errno), errno); + } + + duk_push_array(ctx); + nchanged = 0; + for (i = 0; i < n; i++) { + /* update revents */ + + if (fds[i].revents) { + duk_push_int(ctx, fds[i].fd); /* -> [... retarr fd] */ + duk_put_prop_index(ctx, -2, nchanged); + nchanged++; + } + + duk_push_int(ctx, fds[i].fd); /* -> [... retarr key] */ + duk_get_prop(ctx, 0); /* -> [... retarr val] */ + duk_push_string(ctx, "revents"); + duk_push_int(ctx, fds[i].revents); /* -> [... retarr val "revents" fds[i].revents] */ + duk_put_prop(ctx, -3); /* -> [... retarr val] */ + duk_pop(ctx); + } + + /* [retarr] */ + + return 1; +} + +static duk_function_list_entry poll_funcs[] = { + { "poll", poll_poll, 2 }, + { NULL, NULL, 0 } +}; + +static duk_number_list_entry poll_consts[] = { + { "POLLIN", (double) POLLIN }, + { "POLLPRI", (double) POLLPRI }, + { "POLLOUT", (double) POLLOUT }, +#if 0 + /* Linux 2.6.17 and upwards, requires _GNU_SOURCE etc, not added + * now because we don't use it. + */ + { "POLLRDHUP", (double) POLLRDHUP }, +#endif + { "POLLERR", (double) POLLERR }, + { "POLLHUP", (double) POLLHUP }, + { "POLLNVAL", (double) POLLNVAL }, + { NULL, 0.0 } +}; + +void poll_register(duk_context *ctx) { + /* Set global 'Poll' with functions and constants. */ + duk_push_global_object(ctx); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, poll_funcs); + duk_put_number_list(ctx, -1, poll_consts); + duk_put_prop_string(ctx, -2, "Poll"); + duk_pop(ctx); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/server-socket-test.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/server-socket-test.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/server-socket-test.js new file mode 100644 index 0000000..68510af --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/server-socket-test.js @@ -0,0 +1,34 @@ + +var HOST = 'localhost' +var PORT = 12345; +var EXIT_TIMEOUT = 300e3; + +print('automatic exit after ' + (EXIT_TIMEOUT / 1e3) + ' seconds'); +setTimeout(function () { + print('exit timer'); + EventLoop.requestExit(); +}, EXIT_TIMEOUT); + +print('listen on ' + HOST + ':' + PORT); +EventLoop.server(HOST, PORT, function (fd, addr, port) { + print('new connection on fd ' + fd + ' from ' + addr + ':' + port); + EventLoop.setReader(fd, function (fd, data) { + var b, i, n, x; + + // Handle socket data carefully: if you convert it to a string, + // it may not be valid UTF-8 etc. Here we operate on the data + // directly in the buffer. + + b = data.valueOf(); // ensure we get a plain buffer + n = b.length; + for (i = 0; i < n; i++) { + x = b[i]; + if (x >= 0x61 && x <= 0x7a) { + b[i] = x - 0x20; // uppercase + } + } + + print('read data on fd ' + fd + ', length ' + data.length); + EventLoop.write(fd, data); + }); +}); http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/socket.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/socket.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/socket.c new file mode 100644 index 0000000..a1587fa --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/eventloop/socket.c @@ -0,0 +1,286 @@ +/* + * TCP sockets binding example. + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <netdb.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <time.h> + +#include "duktape.h" + +#define ERROR_FROM_ERRNO(ctx) do { \ + duk_error(ctx, DUK_ERR_ERROR, "%s (errno=%d)", strerror(errno), errno); \ + } while (0) + +static void set_nonblocking(duk_context *ctx, int fd) { + int rc; + int flags; + + rc = fcntl(fd, F_GETFL); + if (rc < 0) { + ERROR_FROM_ERRNO(ctx); + } + flags = rc; + + flags |= O_NONBLOCK; + + rc = fcntl(fd, F_SETFL, flags); + if (rc < 0) { + ERROR_FROM_ERRNO(ctx); + } +} + +static void set_reuseaddr(duk_context *ctx, int fd) { + int val; + int rc; + + val = 1; + rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &val, sizeof(val)); + if (rc != 0) { + ERROR_FROM_ERRNO(ctx); + } +} + +#ifdef __APPLE__ +static void set_nosigpipe(duk_context *ctx, int fd) { + int val; + int rc; + + val = 1; + rc = setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (const void *) &val, sizeof(val)); + if (rc != 0) { + ERROR_FROM_ERRNO(ctx); + } +} +#endif + +static int socket_create_server_socket(duk_context *ctx) { + const char *addr = duk_to_string(ctx, 0); + int port = duk_to_int(ctx, 1); + int sock; + struct sockaddr_in sockaddr; + struct hostent *ent; + struct in_addr **addr_list; + struct in_addr *addr_inet; + int i; + int rc; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + ERROR_FROM_ERRNO(ctx); + } + + set_nonblocking(ctx, sock); + set_reuseaddr(ctx, sock); +#ifdef __APPLE__ + set_nosigpipe(ctx, sock); +#endif + + ent = gethostbyname(addr); + if (!ent) { + ERROR_FROM_ERRNO(ctx); + } + + addr_list = (struct in_addr **) ent->h_addr_list; + addr_inet = NULL; + for (i = 0; addr_list[i]; i++) { + addr_inet = addr_list[i]; + break; + } + if (!addr_inet) { + duk_error(ctx, DUK_ERR_ERROR, "cannot resolve %s", addr); + } + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr = *addr_inet; + + rc = bind(sock, (const struct sockaddr *) &sockaddr, sizeof(sockaddr)); + if (rc < 0) { + ERROR_FROM_ERRNO(ctx); + } + + rc = listen(sock, 10 /*backlog*/); + if (rc < 0) { + (void) close(sock); + ERROR_FROM_ERRNO(ctx); + } + + duk_push_int(ctx, sock); + return 1; +} + +static int socket_close(duk_context *ctx) { + int sock = duk_to_int(ctx, 0); + int rc; + + rc = close(sock); + if (rc < 0) { + ERROR_FROM_ERRNO(ctx); + } + return 0; +} + +static int socket_accept(duk_context *ctx) { + int sock = duk_to_int(ctx, 0); + int rc; + struct sockaddr_in addr; + socklen_t addrlen; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addrlen = sizeof(addr); + + rc = accept(sock, (struct sockaddr *) &addr, &addrlen); + if (rc < 0) { + ERROR_FROM_ERRNO(ctx); + } + + set_nonblocking(ctx, sock); +#ifdef __APPLE__ + set_nosigpipe(ctx, sock); +#endif + + if (addrlen == sizeof(addr)) { + uint32_t tmp = ntohl(addr.sin_addr.s_addr); + + duk_push_object(ctx); + + duk_push_string(ctx, "fd"); + duk_push_int(ctx, rc); + duk_put_prop(ctx, -3); + duk_push_string(ctx, "addr"); + duk_push_sprintf(ctx, "%d.%d.%d.%d", ((tmp >> 24) & 0xff), ((tmp >> 16) & 0xff), ((tmp >> 8) & 0xff), (tmp & 0xff)); + duk_put_prop(ctx, -3); + duk_push_string(ctx, "port"); + duk_push_int(ctx, ntohs(addr.sin_port)); + duk_put_prop(ctx, -3); + + return 1; + } + + return 0; +} + +static int socket_connect(duk_context *ctx) { + const char *addr = duk_to_string(ctx, 0); + int port = duk_to_int(ctx, 1); + int sock; + struct sockaddr_in sockaddr; + struct hostent *ent; + struct in_addr **addr_list; + struct in_addr *addr_inet; + int i; + int rc; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + ERROR_FROM_ERRNO(ctx); + } + + set_nonblocking(ctx, sock); +#ifdef __APPLE__ + set_nosigpipe(ctx, sock); +#endif + + ent = gethostbyname(addr); + if (!ent) { + ERROR_FROM_ERRNO(ctx); + } + + addr_list = (struct in_addr **) ent->h_addr_list; + addr_inet = NULL; + for (i = 0; addr_list[i]; i++) { + addr_inet = addr_list[i]; + break; + } + if (!addr_inet) { + duk_error(ctx, DUK_ERR_ERROR, "cannot resolve %s", addr); + } + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons(port); + sockaddr.sin_addr = *addr_inet; + + rc = connect(sock, (const struct sockaddr *) &sockaddr, (socklen_t) sizeof(sockaddr)); + if (rc < 0) { + if (errno == EINPROGRESS) { +#if 0 + fprintf(stderr, "connect() returned EINPROGRESS as expected, need to poll writability\n"); + fflush(stderr); +#endif + } else { + ERROR_FROM_ERRNO(ctx); + } + } + + duk_push_int(ctx, sock); + return 1; +} + +static int socket_read(duk_context *ctx) { + int sock = duk_to_int(ctx, 0); + char readbuf[1024]; + int rc; + void *data; + + rc = recvfrom(sock, (void *) readbuf, sizeof(readbuf), 0, NULL, NULL); + if (rc < 0) { + ERROR_FROM_ERRNO(ctx); + } + + data = duk_push_fixed_buffer(ctx, rc); + memcpy(data, readbuf, rc); + return 1; +} + +static int socket_write(duk_context *ctx) { + int sock = duk_to_int(ctx, 0); + const char *data; + size_t len; + ssize_t rc; + + data = duk_to_buffer(ctx, 1, &len); + + /* MSG_NOSIGNAL: avoid SIGPIPE */ +#ifdef __APPLE__ + rc = sendto(sock, (void *) data, len, 0, NULL, 0); +#else + rc = sendto(sock, (void *) data, len, MSG_NOSIGNAL, NULL, 0); +#endif + if (rc < 0) { + ERROR_FROM_ERRNO(ctx); + } + + duk_push_int(ctx, rc); + return 1; +} + +static duk_function_list_entry socket_funcs[] = { + { "createServerSocket", socket_create_server_socket, 2 }, + { "close", socket_close, 1 }, + { "accept", socket_accept, 1 }, + { "connect", socket_connect, 2 }, + { "read", socket_read, 1 }, + { "write", socket_write, 2 }, + { NULL, NULL, 0 } +}; + +void socket_register(duk_context *ctx) { + /* Set global 'Socket'. */ + duk_push_global_object(ctx); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, socket_funcs); + duk_put_prop_string(ctx, -2, "Socket"); + duk_pop(ctx); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/README.rst ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/README.rst b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/README.rst new file mode 100644 index 0000000..1933094 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/README.rst @@ -0,0 +1,5 @@ +=========================== +Duktape guide example files +=========================== + +Examples used in the Duktape guide. http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/fib.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/fib.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/fib.js new file mode 100644 index 0000000..2b2982f --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/fib.js @@ -0,0 +1,16 @@ +// fib.js +function fib(n) { + if (n == 0) { return 0; } + if (n == 1) { return 1; } + return fib(n-1) + fib(n-2); +} + +function test() { + var res = []; + for (i = 0; i < 20; i++) { + res.push(fib(i)); + } + print(res.join(' ')); +} + +test(); http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/prime.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/prime.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/prime.js new file mode 100644 index 0000000..8959754 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/prime.js @@ -0,0 +1,32 @@ +// prime.js + +// Pure Ecmascript version of low level helper +function primeCheckEcmascript(val, limit) { + for (var i = 2; i <= limit; i++) { + if ((val % i) == 0) { return false; } + } + return true; +} + +// Select available helper at load time +var primeCheckHelper = (this.primeCheckNative || primeCheckEcmascript); + +// Check 'val' for primality +function primeCheck(val) { + if (val == 1 || val == 2) { return true; } + var limit = Math.ceil(Math.sqrt(val)); + while (limit * limit < val) { limit += 1; } + return primeCheckHelper(val, limit); +} + +// Find primes below one million ending in '9999'. +function primeTest() { + var res = []; + + print('Have native helper: ' + (primeCheckHelper !== primeCheckEcmascript)); + for (var i = 1; i < 1000000; i++) { + if (primeCheck(i) && (i % 10000) == 9999) { res.push(i); } + } + print(res.join(' ')); +} + http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/primecheck.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/primecheck.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/primecheck.c new file mode 100644 index 0000000..36fa5d6 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/primecheck.c @@ -0,0 +1,52 @@ +/* primecheck.c */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "duktape.h" + +static duk_ret_t native_prime_check(duk_context *ctx) { + int val = duk_require_int(ctx, 0); + int lim = duk_require_int(ctx, 1); + int i; + + for (i = 2; i <= lim; i++) { + if (val % i == 0) { + duk_push_false(ctx); + return 1; + } + } + + duk_push_true(ctx); + return 1; +} + +int main(int argc, const char *argv[]) { + duk_context *ctx = NULL; + + ctx = duk_create_heap_default(); + if (!ctx) { + printf("Failed to create a Duktape heap.\n"); + exit(1); + } + + duk_push_global_object(ctx); + duk_push_c_function(ctx, native_prime_check, 2 /*nargs*/); + duk_put_prop_string(ctx, -2, "primeCheckNative"); + + if (duk_peval_file(ctx, "prime.js") != 0) { + printf("Error: %s\n", duk_safe_to_string(ctx, -1)); + goto finished; + } + duk_pop(ctx); /* ignore result */ + + duk_get_prop_string(ctx, -1, "primeTest"); + if (duk_pcall(ctx, 0) != 0) { + printf("Error: %s\n", duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); /* ignore result */ + + finished: + duk_destroy_heap(ctx); + + exit(0); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/process.js ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/process.js b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/process.js new file mode 100644 index 0000000..62b5011 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/process.js @@ -0,0 +1,12 @@ +// process.js +function processLine(line) { + return line.trim() + .replace(/[<>&"'\u0000-\u001F\u007E-\uFFFF]/g, function(x) { + // escape HTML characters + return '&#' + x.charCodeAt(0) + ';' + }) + .replace(/\*(.*?)\*/g, function(x, m) { + // automatically bold text between stars + return '<b>' + m + '</b>'; + }); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/processlines.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/processlines.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/processlines.c new file mode 100644 index 0000000..f91bdff --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/processlines.c @@ -0,0 +1,59 @@ +/* processlines.c */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "duktape.h" + +int main(int argc, const char *argv[]) { + duk_context *ctx = NULL; + char line[4096]; + char idx; + int ch; + + ctx = duk_create_heap_default(); + if (!ctx) { + printf("Failed to create a Duktape heap.\n"); + exit(1); + } + + if (duk_peval_file(ctx, "process.js") != 0) { + printf("Error: %s\n", duk_safe_to_string(ctx, -1)); + goto finished; + } + duk_pop(ctx); /* ignore result */ + + memset(line, 0, sizeof(line)); + idx = 0; + for (;;) { + if (idx >= sizeof(line)) { + printf("Line too long\n"); + exit(1); + } + + ch = fgetc(stdin); + if (ch == 0x0a) { + line[idx++] = '\0'; + + duk_push_global_object(ctx); + duk_get_prop_string(ctx, -1 /*index*/, "processLine"); + duk_push_string(ctx, line); + if (duk_pcall(ctx, 1 /*nargs*/) != 0) { + printf("Error: %s\n", duk_safe_to_string(ctx, -1)); + } else { + printf("%s\n", duk_safe_to_string(ctx, -1)); + } + duk_pop(ctx); /* pop result/error */ + + idx = 0; + } else if (ch == EOF) { + break; + } else { + line[idx++] = (char) ch; + } + } + + finished: + duk_destroy_heap(ctx); + + exit(0); +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/uppercase.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/uppercase.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/uppercase.c new file mode 100644 index 0000000..03d0869 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/guide/uppercase.c @@ -0,0 +1,42 @@ +/* uppercase.c */ +#include <stdio.h> +#include <stdlib.h> +#include "duktape.h" + +static int dummy_upper_case(duk_context *ctx) { + size_t sz; + const char *val = duk_require_lstring(ctx, 0, &sz); + size_t i; + + /* We're going to need 'sz' additional entries on the stack. */ + duk_require_stack(ctx, sz); + + for (i = 0; i < sz; i++) { + char ch = val[i]; + if (ch >= 'a' && ch <= 'z') { + ch = ch - 'a' + 'A'; + } + duk_push_lstring(ctx, (const char *) &ch, 1); + } + + duk_concat(ctx, sz); + return 1; +} + +int main(int argc, char *argv[]) { + duk_context *ctx; + + if (argc < 2) { exit(1); } + + ctx = duk_create_heap_default(); + if (!ctx) { exit(1); } + + duk_push_c_function(ctx, dummy_upper_case, 1); + duk_push_string(ctx, argv[1]); + duk_call(ctx, 1); + printf("%s -> %s\n", argv[1], duk_to_string(ctx, -1)); + duk_pop(ctx); + + duk_destroy_heap(ctx); + return 0; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/README.rst ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/README.rst b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/README.rst new file mode 100644 index 0000000..7afef53 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/README.rst @@ -0,0 +1,5 @@ +=================== +Hello world example +=================== + +Very simple example, most useful for compilation tests. http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/hello.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/hello.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/hello.c new file mode 100644 index 0000000..9113d2f --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/hello/hello.c @@ -0,0 +1,38 @@ +/* + * Very simple example program + */ + +#include "duktape.h" + +int adder(duk_context *ctx) { + int i; + int n = duk_get_top(ctx); /* #args */ + double res = 0.0; + + for (i = 0; i < n; i++) { + res += duk_to_number(ctx, i); + } + + duk_push_number(ctx, res); + return 1; /* one return value */ +} + +int main(int argc, char *argv[]) { + duk_context *ctx = duk_create_heap_default(); + + (void) argc; (void) argv; /* suppress warning */ + + duk_eval_string(ctx, "print('Hello world!');"); + + duk_push_global_object(ctx); + duk_push_c_function(ctx, adder, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "adder"); + duk_pop(ctx); /* pop global */ + + duk_eval_string(ctx, "print('2+3=' + adder(2, 3));"); + duk_pop(ctx); /* pop eval result */ + + duk_destroy_heap(ctx); + + return 0; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/README.rst ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/README.rst b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/README.rst new file mode 100644 index 0000000..5ab43a8 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/README.rst @@ -0,0 +1,5 @@ +================ +Jxpretty example +================ + +Simple command line utility to pretty print JSON in the JX format. http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/jxpretty.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/jxpretty.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/jxpretty.c new file mode 100644 index 0000000..1e483ef --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/jxpretty/jxpretty.c @@ -0,0 +1,63 @@ +/* + * Pretty print JSON from stdin into indented JX. + */ + +#include <stdio.h> +#include <stdlib.h> +#include "duktape.h" + +static duk_ret_t do_jxpretty(duk_context *ctx) { + FILE *f = stdin; + char buf[4096]; + size_t ret; + + for (;;) { + if (ferror(f)) { + duk_error(ctx, DUK_ERR_ERROR, "ferror() on stdin"); + } + if (feof(f)) { + break; + } + + ret = fread(buf, 1, sizeof(buf), f); +#if 0 + fprintf(stderr, "Read: %ld\n", (long) ret); + fflush(stderr); +#endif + if (ret == 0) { + break; + } + + duk_require_stack(ctx, 1); + duk_push_lstring(ctx, (const char *) buf, ret); + } + + duk_concat(ctx, duk_get_top(ctx)); + + duk_eval_string(ctx, "(function (v) { print(Duktape.enc('jx', JSON.parse(v), null, 4)); })"); + duk_insert(ctx, -2); + duk_call(ctx, 1); + + return 0; +} + +int main(int argc, char *argv[]) { + duk_context *ctx; + duk_int_t rc; + + /* suppress warnings */ + (void) argc; + (void) argv; + + ctx = duk_create_heap_default(); + + rc = duk_safe_call(ctx, do_jxpretty, 0 /*nargs*/, 1 /*nrets*/); + if (rc) { + fprintf(stderr, "ERROR: %s\n", duk_safe_to_string(ctx, -1)); + fflush(stderr); + } + + duk_destroy_heap(ctx); + + return 0; +} http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/README.rst ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/README.rst b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/README.rst new file mode 100644 index 0000000..24df0a2 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/README.rst @@ -0,0 +1,5 @@ +=============== +Sandbox example +=============== + +Very simple, minimal sandboxing example. http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/df353561/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/sandbox.c ---------------------------------------------------------------------- diff --git a/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/sandbox.c b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/sandbox.c new file mode 100644 index 0000000..915faa9 --- /dev/null +++ b/thirdparty/civetweb-1.10/src/third_party/duktape-1.5.2/examples/sandbox/sandbox.c @@ -0,0 +1,252 @@ +/* + * Sandboxing example + * + * Uses custom memory allocation functions which keep track of total amount + * of memory allocated, imposing a maximum total allocation size. + */ + +#include <stdio.h> +#include <stdlib.h> +#include "duktape.h" + +/* + * Memory allocator which backs to standard library memory functions but + * keeps a small header to track current allocation size. + * + * Many other sandbox allocation models are useful, e.g. preallocated pools. + */ + +typedef struct { + /* The double value in the union is there to ensure alignment is + * good for IEEE doubles too. In many 32-bit environments 4 bytes + * would be sufficiently aligned and the double value is unnecessary. + */ + union { + size_t sz; + double d; + } u; +} alloc_hdr; + +static size_t total_allocated = 0; +static size_t max_allocated = 256 * 1024; /* 256kB sandbox */ + +static void sandbox_dump_memstate(void) { +#if 0 + fprintf(stderr, "Total allocated: %ld\n", (long) total_allocated); + fflush(stderr); +#endif +} + +static void *sandbox_alloc(void *udata, duk_size_t size) { + alloc_hdr *hdr; + + (void) udata; /* Suppress warning. */ + + if (size == 0) { + return NULL; + } + + if (total_allocated + size > max_allocated) { + fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_alloc\n", + (long) size); + fflush(stderr); + return NULL; + } + + hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr)); + if (!hdr) { + return NULL; + } + hdr->u.sz = size; + total_allocated += size; + sandbox_dump_memstate(); + return (void *) (hdr + 1); +} + +static void *sandbox_realloc(void *udata, void *ptr, duk_size_t size) { + alloc_hdr *hdr; + size_t old_size; + void *t; + + (void) udata; /* Suppress warning. */ + + /* Handle the ptr-NULL vs. size-zero cases explicitly to minimize + * platform assumptions. You can get away with much less in specific + * well-behaving environments. + */ + + if (ptr) { + hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr)); + old_size = hdr->u.sz; + + if (size == 0) { + total_allocated -= old_size; + free((void *) hdr); + sandbox_dump_memstate(); + return NULL; + } else { + if (total_allocated - old_size + size > max_allocated) { + fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n", + (long) size); + fflush(stderr); + return NULL; + } + + t = realloc((void *) hdr, size + sizeof(alloc_hdr)); + if (!t) { + return NULL; + } + hdr = (alloc_hdr *) t; + total_allocated -= old_size; + total_allocated += size; + hdr->u.sz = size; + sandbox_dump_memstate(); + return (void *) (hdr + 1); + } + } else { + if (size == 0) { + return NULL; + } else { + if (total_allocated + size > max_allocated) { + fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n", + (long) size); + fflush(stderr); + return NULL; + } + + hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr)); + if (!hdr) { + return NULL; + } + hdr->u.sz = size; + total_allocated += size; + sandbox_dump_memstate(); + return (void *) (hdr + 1); + } + } +} + +static void sandbox_free(void *udata, void *ptr) { + alloc_hdr *hdr; + + (void) udata; /* Suppress warning. */ + + if (!ptr) { + return; + } + hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr)); + total_allocated -= hdr->u.sz; + free((void *) hdr); + sandbox_dump_memstate(); +} + +/* + * Sandbox setup and test + */ + +static duk_ret_t do_sandbox_test(duk_context *ctx) { + FILE *f; + char buf[4096]; + size_t ret; + const char *globobj; + + /* + * Setup sandbox + */ + + globobj = + "({\n" + " print: print,\n" + " Math: {\n" + " max: Math.max\n" + " }\n" + "})\n"; +#if 1 + fprintf(stderr, "Sandbox global object:\n----------------\n%s----------------\n", globobj); + fflush(stderr); +#endif + duk_eval_string(ctx, globobj); + duk_set_global_object(ctx); + + /* + * Execute code from specified file + */ + + f = fopen(duk_require_string(ctx, -1), "rb"); + if (!f) { + duk_error(ctx, DUK_ERR_ERROR, "failed to open file"); + } + + for (;;) { + if (ferror(f)) { + fclose(f); + duk_error(ctx, DUK_ERR_ERROR, "ferror when reading file"); + } + if (feof(f)) { + break; + } + + ret = fread(buf, 1, sizeof(buf), f); + if (ret == 0) { + break; + } + + duk_push_lstring(ctx, (const char *) buf, ret); + } + + duk_concat(ctx, duk_get_top(ctx) - 1); /* -1 for filename */ + + /* -> [ ... filename source ] */ + + duk_insert(ctx, -2); + + /* -> [ ... source filename ] */ + + duk_compile(ctx, 0 /*flags*/); /* Compile as program */ + duk_call(ctx, 0 /*nargs*/); + + return 0; +} + +/* + * Main + */ + +static void sandbox_fatal(duk_context *ctx, duk_errcode_t code, const char *msg) { + (void) ctx; /* Suppress warning. */ + fprintf(stderr, "FATAL %ld: %s\n", (long) code, (msg ? msg : "no message")); + fflush(stderr); + exit(1); /* must not return */ +} + +int main(int argc, char *argv[]) { + duk_context *ctx; + duk_int_t rc; + + if (argc < 2) { + fprintf(stderr, "Usage: sandbox <test.js>\n"); + fflush(stderr); + exit(1); + } + + ctx = duk_create_heap(sandbox_alloc, + sandbox_realloc, + sandbox_free, + NULL, + sandbox_fatal); + + duk_push_string(ctx, argv[1]); + rc = duk_safe_call(ctx, do_sandbox_test, 1 /*nargs*/, 1 /*nrets*/); + if (rc) { + fprintf(stderr, "ERROR: %s\n", duk_safe_to_string(ctx, -1)); + fflush(stderr); + } + + duk_destroy_heap(ctx); + + /* Should be zero. */ + fprintf(stderr, "Final allocation: %ld\n", (long) total_allocated); + fflush(stderr); + + return 1; +}