wota now encodes at the C level; update dmon for macos 13; clean up many warnings
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m15s
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled

This commit is contained in:
2025-03-20 17:25:48 -05:00
parent c566f90d16
commit 95d3296dd9
22 changed files with 1021 additions and 443 deletions

View File

@@ -32,8 +32,9 @@ add_project_arguments(
add_project_arguments('-Wno-incompatible-pointer-types', language: 'c')
add_project_arguments('-Wno-narrowing', language: 'cpp')
add_project_arguments('-Wno-missing-braces', language:'c')
add_project_arguments('-Wl,--disable-new-dtags', language:'cpp')
add_project_arguments('-Wl,--disable-new-dtags', language:'c')
add_project_arguments('-Wno-strict-prototypes', language:'c')
add_project_arguments('-Wno-unused-command-line-argument', language: 'c')
add_project_arguments('-Wno-unused-command-line-argument', language: 'cpp')
deps = []
@@ -236,7 +237,8 @@ tests = [
'wota',
'portalspawner',
'overling',
'send'
'send',
'delay'
]
foreach file : tests

View File

@@ -575,7 +575,6 @@ var enet = use('enet')
var util = use('util')
var math = use('math')
var crypto = use('crypto')
var wota = use('wota')
var nota = use('nota')
var HEADER = Symbol()
@@ -671,6 +670,10 @@ var portal_fn = undefined
var local_address = undefined
var local_port = undefined
var service_delay = 0.01
$_.portal = function(fn, port) {
if (portal) throw new Error(`Already started a portal listening on ${portal.port}`)
console.log(`starting a portal on port ${port}`)
@@ -680,6 +683,7 @@ $_.portal = function(fn, port) {
local_port = port
portal_fn = fn
console.log(`I am now ${$_}`)
// kick off servicing
}
$_.portal[prosperon.DOC] = "starts a public address that performs introduction services..."
@@ -744,7 +748,6 @@ $_.start[prosperon.DOC] = "The start function creates a new actor..."
$_.stop = function(actor) {
if (!actor) {
destroyself()
return
}
@@ -791,7 +794,7 @@ function actor_send(actor, message) {
}
if (actor.__ACTORDATA__.id && os.mailbox_exist(actor.__ACTORDATA__.id)) {
os.mailbox_push(actor.__ACTORDATA__.id, wota.encode(message))
os.mailbox_push(actor.__ACTORDATA__.id, message)
return
}
@@ -847,7 +850,7 @@ cmd.process(prosperon.argv)
if (!prosperon.args.id) prosperon.id = util.guid()
else prosperon.id = prosperon.args.id
os.register_actor(prosperon.id, handle_local);
os.register_actor(prosperon.id, handle_message);
$_.__ACTORDATA__.id = prosperon.id
@@ -860,8 +863,8 @@ if (prosperon.args.program) actor.spawn(prosperon.args.program)
function destroyself() {
console.log(`Got the message to destroy self.`)
if (overling) actor_send(overling, { type: "stopped", id: prosperon.id })
os.destroy(prosperon.id);
// if (overling) actor_send(overling, { type: "stopped", id: prosperon.id })
os.destroy();
}
function handle_actor_disconnect(id) {
@@ -875,17 +878,11 @@ function handle_actor_disconnect(id) {
delete peers[id]
}
function handle_local(msg) {
console.print("LOCAL!!!");
console.log("LOCAL MESSAGE");
handle_message(wota.decode(msg))
}
function handle_message(msg) {
console.log(`message was ${json.encode(msg)}`)
if (msg.target) {
if (msg.target !== prosperon.id) {
os.mailbox_push(msg.target, wota.encode(msg))
os.mailbox_push(msg.target, msg)
return
}
}
@@ -933,6 +930,4 @@ function handle_message(msg) {
}
};
console.log('finished running main')
})()

View File

@@ -306,7 +306,7 @@ struct ase_t
void* mem_ctx;
};
const char *aseprite_GetError();
const char *aseprite_GetError(void);
#endif // CUTE_ASEPRITE_H
@@ -317,11 +317,11 @@ const char *aseprite_GetError();
#define ASEPRITE_ERROR_MAX 256
char aseprite_error[ASEPRITE_ERROR_MAX] = {0};
const char *aseprite_GetError() {
const char *aseprite_GetError(void) {
return aseprite_error;
}
void aseprite_clear_error() {
void aseprite_clear_error(void) {
aseprite_error[0] = 0;
}
@@ -726,7 +726,6 @@ static int s_inflate(const void* in, int in_bytes, void* out, int out_bytes, voi
s->out_end = s->out + out_bytes;
s->begin = (char*)out;
int count = 0;
uint32_t bfinal;
do
{
@@ -740,8 +739,6 @@ static int s_inflate(const void* in, int in_bytes, void* out, int out_bytes, voi
case 2: s_dynamic(s); CUTE_ASEPRITE_CALL(s_block(s)); break;
case 3: CUTE_ASEPRITE_CHECK(0, "Detected unknown block type within input stream.");
}
++count;
}
while (!bfinal);

View File

@@ -891,9 +891,7 @@ _DMON_PRIVATE void _dmon_inotify_process_events(void)
ev->skip = true;
break;
} else if ((ev->mask & IN_ISDIR) && (check_ev->mask & (IN_ISDIR|IN_MODIFY))) {
// in some cases, particularly when created files under sub directories
// there can be two modify events for a single subdir one with trailing slash and one without
// remove trailing slash from both cases and test
// handle trailing slashes
int l1 = (int)strlen(ev->filepath);
int l2 = (int)strlen(check_ev->filepath);
if (ev->filepath[l1-1] == '/') ev->filepath[l1-1] = '\0';
@@ -910,14 +908,12 @@ _DMON_PRIVATE void _dmon_inotify_process_events(void)
for (j = i + 1; j < c && !loop_break; j++) {
dmon__inotify_event* check_ev = &_dmon.events[j];
if ((check_ev->mask & IN_MOVED_FROM) && strcmp(ev->filepath, check_ev->filepath) == 0) {
// there is a case where some programs (like gedit):
// when we save, it creates a temp file, and moves it to the file being modified
// search for these cases and remove all of them
// check for rename sequences
int k;
for (k = j + 1; k < c; k++) {
dmon__inotify_event* third_ev = &_dmon.events[k];
if (third_ev->mask & IN_MOVED_TO && check_ev->cookie == third_ev->cookie) {
third_ev->mask = IN_MODIFY; // change to modified
third_ev->mask = IN_MODIFY; // treat as a modify
ev->skip = check_ev->skip = true;
loop_break = true;
break;
@@ -925,7 +921,6 @@ _DMON_PRIVATE void _dmon_inotify_process_events(void)
}
} else if ((check_ev->mask & IN_MODIFY) && strcmp(ev->filepath, check_ev->filepath) == 0) {
// Another case is that file is copied. CREATE and MODIFY happens sequentially
// so we ignore MODIFY event
check_ev->skip = true;
}
}
@@ -939,10 +934,7 @@ _DMON_PRIVATE void _dmon_inotify_process_events(void)
break;
}
}
// in some environments like nautilus file explorer:
// when a file is deleted, it is moved to recycle bin
// so if the destination of the move is not valid, it's probably DELETE
// If destination is not valid, treat as delete
if (!move_valid) {
ev->mask = IN_DELETE;
}
@@ -956,10 +948,7 @@ _DMON_PRIVATE void _dmon_inotify_process_events(void)
break;
}
}
// in some environments like nautilus file explorer:
// when a file is deleted, it is moved to recycle bin, on undo it is moved back it
// so if the destination of the move is not valid, it's probably CREATE
// If source is not valid, treat as create
if (!move_valid) {
ev->mask = IN_CREATE;
}
@@ -967,7 +956,6 @@ _DMON_PRIVATE void _dmon_inotify_process_events(void)
int j;
for (j = i + 1; j < c; j++) {
dmon__inotify_event* check_ev = &_dmon.events[j];
// if the file is DELETED and then MODIFIED after, just ignore the modify event
if ((check_ev->mask & IN_MODIFY) && strcmp(ev->filepath, check_ev->filepath) == 0) {
check_ev->skip = true;
break;
@@ -1009,10 +997,9 @@ _DMON_PRIVATE void _dmon_inotify_process_events(void)
stb_sb_push(watch->subdirs, subdir);
stb_sb_push(watch->wds, wd);
// some directories may be already created, for instance, with the command: mkdir -p
// so we will enumerate them manually and add them to the events
// gather newly created subdirs
_dmon_gather_recursive(watch, watchdir);
ev = &_dmon.events[i]; // gotta refresh the pointer because it may be relocated
ev = &_dmon.events[i];
}
}
watch->watch_cb(ev->watch_id, DMON_ACTION_CREATE, watch->rootdir, ev->filepath, NULL, watch->user_data);
@@ -1256,7 +1243,7 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir,
return _dmon_make_id(0);
}
dmon__watch_subdir subdir;
_dmon_strcpy(subdir.rootdir, sizeof(subdir.rootdir), ""); // root dir is just a dummy entry
_dmon_strcpy(subdir.rootdir, sizeof(subdir.rootdir), ""); // root dir is a dummy entry
stb_sb_push(watch->subdirs, subdir);
stb_sb_push(watch->wds, wd);
@@ -1369,7 +1356,7 @@ _DMON_PRIVATE void _dmon_fsevent_process_events(void)
continue;
}
// remove redundant modify events on a single file
// remove redundant modifies on a single file
if (ev->event_flags & kFSEventStreamEventFlagItemModified) {
int j;
for (j = i + 1; j < c; j++) {
@@ -1380,7 +1367,8 @@ _DMON_PRIVATE void _dmon_fsevent_process_events(void)
break;
}
}
} else if ((ev->event_flags & kFSEventStreamEventFlagItemRenamed) && !ev->move_valid) {
}
else if ((ev->event_flags & kFSEventStreamEventFlagItemRenamed) && !ev->move_valid) {
int j;
for (j = i + 1; j < c; j++) {
dmon__fsevent_event* check_ev = &_dmon.events[j];
@@ -1391,10 +1379,7 @@ _DMON_PRIVATE void _dmon_fsevent_process_events(void)
}
}
// in some environments like finder file explorer:
// when a file is deleted, it is moved to recycle bin
// so if the destination of the move is not valid, it's probably DELETE or CREATE
// decide CREATE if file exists
// if not valid rename, treat as remove or create
if (!ev->move_valid) {
ev->event_flags &= ~kFSEventStreamEventFlagItemRenamed;
@@ -1429,10 +1414,10 @@ _DMON_PRIVATE void _dmon_fsevent_process_events(void)
watch->watch_cb(ev->watch_id, DMON_ACTION_CREATE, watch->rootdir_unmod, ev->filepath, NULL,
watch->user_data);
}
if (ev->event_flags & kFSEventStreamEventFlagItemModified) {
watch->watch_cb(ev->watch_id, DMON_ACTION_MODIFY, watch->rootdir_unmod, ev->filepath, NULL, watch->user_data);
} else if (ev->event_flags & kFSEventStreamEventFlagItemRenamed) {
}
else if (ev->event_flags & kFSEventStreamEventFlagItemRenamed) {
int j;
for (j = i + 1; j < c; j++) {
dmon__fsevent_event* check_ev = &_dmon.events[j];
@@ -1442,7 +1427,8 @@ _DMON_PRIVATE void _dmon_fsevent_process_events(void)
break;
}
}
} else if (ev->event_flags & kFSEventStreamEventFlagItemRemoved) {
}
else if (ev->event_flags & kFSEventStreamEventFlagItemRemoved) {
watch->watch_cb(ev->watch_id, DMON_ACTION_DELETE, watch->rootdir_unmod, ev->filepath, NULL,
watch->user_data);
}
@@ -1478,8 +1464,19 @@ _DMON_PRIVATE void* _dmon_thread(void* arg)
dmon__watch_state* watch = _dmon.watches[i];
if (!watch->init) {
DMON_ASSERT(watch->fsev_stream_ref);
// Modified block: Use dispatch queue if macOS >= 13, else run loop
#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 130000
{
dispatch_queue_t queue = dispatch_queue_create("com.dmon.fsevents", DISPATCH_QUEUE_SERIAL);
FSEventStreamSetDispatchQueue(watch->fsev_stream_ref, queue);
FSEventStreamStart(watch->fsev_stream_ref);
}
#else
{
FSEventStreamScheduleWithRunLoop(watch->fsev_stream_ref, _dmon.cf_loop_ref, kCFRunLoopDefaultMode);
FSEventStreamStart(watch->fsev_stream_ref);
}
#endif
watch->init = true;
}
@@ -1587,8 +1584,8 @@ _DMON_PRIVATE void _dmon_fsevent_callback(ConstFSEventStreamRef stream_ref, void
_dmon_strcpy(abs_filepath, sizeof(abs_filepath), filepath);
_dmon_unixpath(abs_filepath, sizeof(abs_filepath), abs_filepath);
// normalize path, so it would be the same on both MacOS file-system types (case/nocase)
_dmon_tolower(abs_filepath_lower, sizeof(abs_filepath), abs_filepath);
// normalize path for case-insensitive volumes
_dmon_tolower(abs_filepath_lower, sizeof(abs_filepath_lower), abs_filepath);
DMON_ASSERT(strstr(abs_filepath_lower, watch->rootdir) == abs_filepath_lower);
// strip the root dir from the beginning
@@ -1707,7 +1704,6 @@ DMON_API_IMPL dmon_watch_id dmon_watch(const char* rootdir,
cf_dirarr, kFSEventStreamEventIdSinceNow, 0.25,
kFSEventStreamCreateFlagFileEvents);
CFRelease(cf_dirarr);
CFRelease(cf_dir);

View File

@@ -225,8 +225,6 @@ JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \
TARGET = js2##TYPE(JS, __##PROP##__v); \
JS_FreeValue(JS,__##PROP##__v); }\
#define JS_SetProperty(js, target, atom, val) JS_SetPropertyStr(js, target, #atom, val)
#define JS_SETATOM(JS, TARGET, ATOM, VALUE, TYPE) JS_SetProperty(JS, TARGET, #ATOM, TYPE##2js(JS, VALUE));
int JS_GETBOOL(JSContext *js, JSValue v, const char *prop)
@@ -1057,7 +1055,7 @@ void SDL_GPURenderPass_free(JSRuntime *rt, SDL_GPURenderPass *c) { }
#define GPURELEASECLASS(NAME) \
void SDL_GPU##NAME##_free(JSRuntime *rt, SDL_GPU##NAME *c) { \
SDL_ReleaseGPU##NAME(global_gpu, c); } \
QJSCLASS(SDL_GPU##NAME) \
QJSCLASS(SDL_GPU##NAME,) \
static JSClassID js_sprite_id;
static void js_sprite_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
@@ -1065,7 +1063,7 @@ static void js_sprite_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_fu
if (!sp) return;
JS_MarkValue(rt, sp->image, mark_func);
}
QJSCLASSMARK(sprite)
QJSCLASSMARK(sprite,)
static JSClassID js_transform_id;
static void js_transform_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func) {
@@ -1080,12 +1078,12 @@ static void js_transform_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark
JS_MarkValue(rt, t->jschildren[i], mark_func);
}
QJSCLASSMARK(transform)
QJSCLASS(font)
QJSCLASS(datastream)
QJSCLASS(SDL_Window)
QJSCLASS(SDL_Renderer)
QJSCLASS(SDL_Camera)
QJSCLASSMARK(transform,)
QJSCLASS(font,)
QJSCLASS(datastream,)
QJSCLASS(SDL_Window,)
QJSCLASS(SDL_Renderer,)
QJSCLASS(SDL_Camera,)
void SDL_Texture_free(JSRuntime *rt, SDL_Texture *t){
SDL_DestroyTexture(t);
@@ -1101,8 +1099,8 @@ QJSCLASS(SDL_Surface,
JS_SetProperty(js,j,height_atom,number2js(js,n->h));
)
QJSCLASS(SDL_GPUDevice)
QJSCLASS(SDL_Thread)
QJSCLASS(SDL_GPUDevice,)
QJSCLASS(SDL_Thread,)
GPURELEASECLASS(Buffer)
GPURELEASECLASS(ComputePipeline)
@@ -1113,25 +1111,25 @@ GPURELEASECLASS(Texture)
GPURELEASECLASS(TransferBuffer)
GPURELEASECLASS(Fence)
QJSCLASS(SDL_GPUCommandBuffer)
QJSCLASS(SDL_GPUComputePass)
QJSCLASS(SDL_GPUCopyPass)
QJSCLASS(SDL_GPURenderPass)
QJSCLASS(SDL_Cursor)
QJSCLASS(SDL_GPUCommandBuffer,)
QJSCLASS(SDL_GPUComputePass,)
QJSCLASS(SDL_GPUCopyPass,)
QJSCLASS(SDL_GPURenderPass,)
QJSCLASS(SDL_Cursor,)
static void PHYSFS_File_free(JSRuntime *rt, PHYSFS_File *f)
{
PHYSFS_close(f);
}
QJSCLASS(PHYSFS_File)
QJSCLASS(PHYSFS_File,)
void rtree_free(JSRuntime *rt, rtree *tree)
{
rtree_destroy(tree);
}
QJSCLASS(rtree)
QJSCLASS(rtree,)
int js_arrlen(JSContext *js,JSValue v) {
if (JS_IsUndefined(v)) return 0;
@@ -2661,194 +2659,6 @@ static JSValue js_keymod(JSContext *js)
return ret;
}
static JSValue event2js(JSContext *js, SDL_Event event)
{
JSValue e = JS_NewObject(js);
JS_SetPropertyStr(js, e, "type", JS_AtomToString(js, event_type_to_atom(js, event.type)));
JS_SetPropertyStr(js,e,"timestamp", number2js(js,event.common.timestamp));
switch(event.type) {
case SDL_EVENT_AUDIO_DEVICE_ADDED:
case SDL_EVENT_AUDIO_DEVICE_REMOVED:
JS_SetPropertyStr(js,e,"which", number2js(js,event.adevice.which));
JS_SetPropertyStr(js,e,"recording", JS_NewBool(js,event.adevice.recording));
break;
case SDL_EVENT_DISPLAY_ORIENTATION:
case SDL_EVENT_DISPLAY_ADDED:
case SDL_EVENT_DISPLAY_REMOVED:
case SDL_EVENT_DISPLAY_MOVED:
case SDL_EVENT_DISPLAY_DESKTOP_MODE_CHANGED:
case SDL_EVENT_DISPLAY_CURRENT_MODE_CHANGED:
case SDL_EVENT_DISPLAY_CONTENT_SCALE_CHANGED:
JS_SetPropertyStr(js,e,"which", number2js(js,event.display.displayID));
JS_SetPropertyStr(js,e,"data1", number2js(js,event.display.data1));
JS_SetPropertyStr(js,e,"data2", number2js(js,event.display.data2));
break;
case SDL_EVENT_MOUSE_MOTION:
JS_SetPropertyStr(js,e,"window", number2js(js,event.motion.windowID));
JS_SetPropertyStr(js,e,"which", number2js(js,event.motion.which));
JS_SetPropertyStr(js, e, "state", number2js(js,event.motion.state));
JS_SetPropertyStr(js,e, "pos", vec22js(js,(HMM_Vec2){event.motion.x,event.motion.y}));
JS_SetPropertyStr(js,e,"d_pos", vec22js(js,(HMM_Vec2){event.motion.xrel, event.motion.yrel}));
break;
case SDL_EVENT_MOUSE_WHEEL:
JS_SetPropertyStr(js,e,"window", number2js(js,event.wheel.windowID));
JS_SetPropertyStr(js,e,"which", number2js(js,event.wheel.which));
JS_SetPropertyStr(js,e,"scroll", vec22js(js,(HMM_Vec2){event.wheel.x,event.wheel.y}));
JS_SetPropertyStr(js,e, "mouse", vec22js(js,(HMM_Vec2){event.wheel.mouse_x,event.wheel.mouse_y}));
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
JS_SetPropertyStr(js,e,"window", number2js(js,event.button.windowID));
JS_SetPropertyStr(js,e,"which", number2js(js,event.button.which));
JS_SetPropertyStr(js,e,"down", JS_NewBool(js,event.button.down));
JS_SetPropertyStr(js,e,"button", JS_AtomToString(js,mouse2atom(js,event.button.button)));
JS_SetPropertyStr(js,e,"clicks", number2js(js,event.button.clicks));
JS_SetPropertyStr(js,e,"mouse", vec22js(js,(HMM_Vec2){event.button.x,event.button.y}));
break;
case SDL_EVENT_SENSOR_UPDATE:
JS_SetPropertyStr(js,e,"which", number2js(js,event.sensor.which));
JS_SetPropertyStr(js,e, "sensor_timestamp", number2js(js,event.sensor.sensor_timestamp));
break;
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
JS_SetPropertyStr(js,e,"window", number2js(js,event.key.windowID));
JS_SetPropertyStr(js,e,"which", number2js(js,event.key.which));
JS_SetPropertyStr(js,e,"down", JS_NewBool(js,event.key.down));
JS_SetPropertyStr(js,e,"repeat", JS_NewBool(js,event.key.repeat));
JS_SetPropertyStr(js,e,"key", number2js(js,event.key.key));
JS_SetPropertyStr(js,e,"scancode", number2js(js,event.key.scancode));
JS_SetPropertyStr(js,e,"mod", js_keymod(js));
break;
case SDL_EVENT_FINGER_MOTION:
case SDL_EVENT_FINGER_DOWN:
case SDL_EVENT_FINGER_UP:
JS_SetPropertyStr(js,e,"touch", number2js(js,event.tfinger.touchID));
JS_SetPropertyStr(js,e,"finger", number2js(js,event.tfinger.fingerID));
JS_SetPropertyStr(js,e,"pos", vec22js(js, (HMM_Vec2){event.tfinger.x, event.tfinger.y}));
JS_SetPropertyStr(js,e,"d_pos", vec22js(js,(HMM_Vec2){event.tfinger.x, event.tfinger.dy}));
JS_SetPropertyStr(js,e,"pressure", number2js(js,event.tfinger.pressure));
JS_SetPropertyStr(js,e,"window", number2js(js,event.key.windowID));
break;
case SDL_EVENT_DROP_BEGIN:
case SDL_EVENT_DROP_FILE:
case SDL_EVENT_DROP_TEXT:
case SDL_EVENT_DROP_COMPLETE:
case SDL_EVENT_DROP_POSITION:
JS_SetPropertyStr(js,e,"window", number2js(js,event.drop.windowID));
JS_SetPropertyStr(js,e,"pos", vec22js(js, (HMM_Vec2){event.drop.x,event.drop.y}));
JS_SetPropertyStr(js,e,"data", JS_NewString(js,event.drop.data));
JS_SetPropertyStr(js,e,"source",JS_NewString(js,event.drop.source));
break;
case SDL_EVENT_TEXT_INPUT:
JS_SetPropertyStr(js,e,"window", number2js(js,event.text.windowID));
JS_SetPropertyStr(js,e,"text", JS_NewString(js,event.text.text));
JS_SetPropertyStr(js,e,"mod", js_keymod(js));
break;
case SDL_EVENT_CAMERA_DEVICE_APPROVED:
case SDL_EVENT_CAMERA_DEVICE_REMOVED:
case SDL_EVENT_CAMERA_DEVICE_ADDED:
case SDL_EVENT_CAMERA_DEVICE_DENIED:
JS_SetPropertyStr(js, e, "which", number2js(js,event.cdevice.which));
break;
case SDL_EVENT_CLIPBOARD_UPDATE:
JS_SetPropertyStr(js, e, "owner", JS_NewBool(js,event.clipboard.owner));
break;
case SDL_EVENT_WINDOW_SHOWN:
case SDL_EVENT_WINDOW_HIDDEN:
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_MOVED:
case SDL_EVENT_WINDOW_RESIZED:
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
case SDL_EVENT_WINDOW_METAL_VIEW_RESIZED:
case SDL_EVENT_WINDOW_MINIMIZED:
case SDL_EVENT_WINDOW_MAXIMIZED:
case SDL_EVENT_WINDOW_RESTORED:
case SDL_EVENT_WINDOW_MOUSE_ENTER:
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
case SDL_EVENT_WINDOW_HIT_TEST:
case SDL_EVENT_WINDOW_ICCPROF_CHANGED:
case SDL_EVENT_WINDOW_DISPLAY_CHANGED:
case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
case SDL_EVENT_WINDOW_SAFE_AREA_CHANGED:
case SDL_EVENT_WINDOW_OCCLUDED:
case SDL_EVENT_WINDOW_ENTER_FULLSCREEN:
case SDL_EVENT_WINDOW_LEAVE_FULLSCREEN:
case SDL_EVENT_WINDOW_DESTROYED:
case SDL_EVENT_WINDOW_HDR_STATE_CHANGED:
/* rest of SDL_EVENT_WINDOW_ here */
JS_SetPropertyStr(js,e,"which", number2js(js, event.window.windowID));
JS_SetPropertyStr(js,e,"data1", number2js(js, event.window.data1));
JS_SetPropertyStr(js,e,"data2", number2js(js, event.window.data2));
break;
case SDL_EVENT_JOYSTICK_ADDED:
case SDL_EVENT_JOYSTICK_REMOVED:
case SDL_EVENT_JOYSTICK_UPDATE_COMPLETE:
JS_SetPropertyStr(js,e,"which", number2js(js,event.jdevice.which));
break;
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
JS_SetPropertyStr(js,e,"which", number2js(js,event.jaxis.which));
JS_SetPropertyStr(js,e,"axis", number2js(js,event.jaxis.axis));
JS_SetPropertyStr(js,e,"value", number2js(js,event.jaxis.value));
break;
case SDL_EVENT_JOYSTICK_BALL_MOTION:
JS_SetPropertyStr(js,e,"which", number2js(js,event.jball.which));
JS_SetPropertyStr(js,e,"ball",number2js(js,event.jball.ball));
JS_SetPropertyStr(js,e, "rel", vec22js(js,(HMM_Vec2){event.jball.xrel,event.jball.yrel}));
break;
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
JS_SetPropertyStr(js,e,"which", number2js(js,event.jbutton.which));
JS_SetPropertyStr(js,e,"button", number2js(js,event.jbutton.button));
JS_SetPropertyStr(js,e,"down", JS_NewBool(js,event.jbutton.down));
break;
case SDL_EVENT_GAMEPAD_ADDED:
case SDL_EVENT_GAMEPAD_REMOVED:
case SDL_EVENT_GAMEPAD_REMAPPED:
case SDL_EVENT_GAMEPAD_UPDATE_COMPLETE:
case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
JS_SetPropertyStr(js,e,"which", number2js(js,event.gdevice.which));
break;
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
JS_SetPropertyStr(js,e,"which", number2js(js,event.gaxis.which));
JS_SetPropertyStr(js,e,"axis", number2js(js,event.gaxis.axis));
JS_SetPropertyStr(js,e,"value", number2js(js,event.gaxis.value));
break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
JS_SetPropertyStr(js,e,"which", number2js(js,event.gbutton.which));
JS_SetPropertyStr(js,e,"button", number2js(js,event.gbutton.button));
JS_SetPropertyStr(js,e,"down", JS_NewBool(js,event.gbutton.down));
break;
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
JS_SetPropertyStr(js,e,"which", number2js(js,event.gtouchpad.which));
JS_SetPropertyStr(js,e,"touchpad", number2js(js,event.gtouchpad.touchpad));
JS_SetPropertyStr(js,e,"finger", number2js(js,event.gtouchpad.finger));
JS_SetPropertyStr(js,e,"pos", vec22js(js,(HMM_Vec2){event.gtouchpad.x,event.gtouchpad.y}));
JS_SetPropertyStr(js,e,"pressure", number2js(js,event.gtouchpad.pressure));
break;
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
JS_SetPropertyStr(js,e,"which", number2js(js,event.gsensor.which));
JS_SetPropertyStr(js,e,"sensor", number2js(js,event.gsensor.sensor));
JS_SetPropertyStr(js,e,"sensor_timestamp", number2js(js,event.gsensor.sensor_timestamp));
break;
case SDL_EVENT_USER:
JS_SetPropertyStr(js,e,"cb", JS_DupValue(js,*(JSValue*)event.user.data1));
JS_FreeValue(js,*(JSValue*)event.user.data1);
free(event.user.data1);
event.user.data1 = NULL;
break;
}
return e;
}
JSC_CCALL(camera_list,
int num;
SDL_CameraID *ids = SDL_GetCameras(&num);
@@ -5963,8 +5773,6 @@ JSC_CCALL(io_searchpath,
JS_SetPropertyUint32(js,ret,i,JS_NewString(js,paths[i]));
)
extern void prosperon_mount_core();
JSC_CCALL(io_mount_core,
int mount = JS_ToBool(js,argv[0]);
if (!mount)
@@ -7070,27 +6878,25 @@ JSC_CCALL(os_createactor,
create_actor(margc, margv);
)
#include "qjs_wota.h"
JSC_CCALL(os_mailbox_push,
if (argc < 2) return JS_ThrowInternalError(js, "Need an actor and a message");
if (!JS_IsArrayBuffer(js, argv[1])) return JS_ThrowInternalError(js, "Object to push must be an array buffer");
if (!JS_IsObject(argv[1])) return JS_ThrowInternalError(js, "Object to push must be an object.");
const char *id = JS_ToCString(js, argv[0]);
prosperon_rt *target = get_actor(id);
int exist = actor_exists(id);
JS_FreeCString(js,id);
if (!target)
if (!exist)
return JS_ThrowInternalError(js, "No mailbox found for given ID");
size_t size;
uint8_t *buf = JS_GetArrayBuffer(js, &size, argv[1]);
if (!buf) return JS_ThrowInternalError(js, "Could not get data from arraybuffer");
void *data = value2wota(js, argv[1]);
void *data = js_malloc_rt(JS_GetRuntime(js), size);
if (!data) return JS_ThrowInternalError(js, "Memory allocation failed");
memcpy(data, buf, size);
struct message msg = {data, size};
send_message(target, msg);
char *err = send_message(id, data);
if (err) {
free(data);
return JS_ThrowInternalError(js, "Could not send message: %s", err);
}
)
JSC_CCALL(os_register_actor,
@@ -7101,15 +6907,14 @@ JSC_CCALL(os_register_actor,
rt->message_handle = JS_DupValue(js, argv[1]);
rt->context = js;
JS_FreeCString(js, id);
printf("registered actor at %p with id %s, with function %p\n", rt, id, JS_VALUE_GET_PTR(rt->message_handle));
)
JSC_CCALL(os_mailbox_exist,
const char *id = JS_ToCString(js, argv[0]);
prosperon_rt *actor = get_actor(id);
int exist = actor_exists(id);
JS_FreeCString(js, id);
return JS_NewBool(js, actor ? 1 : 0);
return JS_NewBool(js, exist);
)
JSC_CCALL(os_unneeded,
@@ -7131,7 +6936,7 @@ JSValue js_os_set_trace(JSContext *js, JSValue self, JSValue value)
JSC_CCALL(os_destroy,
prosperon_rt *rt = JS_GetContextOpaque(js);
actor_free(rt);
rt->need_stop = 1;
)
static const JSCFunctionListEntry js_os_funcs[] = {

View File

@@ -29,7 +29,7 @@
#define NOTA_EXP_SIGN(CHAR) (CHAR & (1<<4))
#define NOTA_TYPE 0x70
#define NOTA_HEAD_DATA 0x0f
#define CONTINUE(CHAR) ((CHAR)>>7)
#define CONTINUE(CHAR) (CHAR>>7)
#define UTF8_DATA 0x3f
/* A helper to get the high-level Nota type nibble from a byte */

File diff suppressed because it is too large Load Diff

View File

@@ -31,11 +31,6 @@ typedef struct {
char **argv;
} cmdargs;
struct message {
void *data;
size_t size;
};
typedef struct prosperon_rt {
cmdargs cmd;
JSContext *context;
@@ -44,11 +39,15 @@ typedef struct prosperon_rt {
JSValue on_exception;
JSValue message_handle;
JSValue unneeded;
struct { Uint32 key; JSValue value; } *timers;
/* The queue of JS callbacks triggered by timers or other signals */
JSValue *events;
ModuleEntry *module_registry;
JSValue *js_swapchains;
/* Protects JSContext usage, actor->state, etc. */
SDL_Mutex *mutex;
char *id;
@@ -56,22 +55,26 @@ typedef struct prosperon_rt {
double unneeded_secs;
int idx_count;
struct message *messages;
SDL_Mutex *msg_mutex;
/* The “mailbox” for incoming messages + a dedicated lock for it: */
void **messages;
SDL_Mutex *msg_mutex; /* For messages queue only */
/* CHANGED FOR EVENTS: a separate lock for the actor->events queue */
struct { Uint32 key; JSValue value; } *timers;
SDL_Mutex *evt_mutex; /* For events queue only, and timer hash */
int state;
Uint32 ar;
int need_stop;
} prosperon_rt;
extern SDL_ThreadID main_thread;
extern SDL_TLSID prosperon_id;
prosperon_rt *create_actor(int argc, char **argv);
prosperon_rt *get_actor(char *id);
void create_actor(int argc, char **argv);
char *register_actor(char *id, prosperon_rt *actor);
void actor_signal(prosperon_rt *actor);
void send_message(prosperon_rt *actor, struct message msg);
void actor_turn(prosperon_rt *actor);
void actor_free(prosperon_rt *actor);
char *send_message(char *id, void *msg);
Uint32 actor_timer_cb(prosperon_rt *actor, SDL_TimerID id, Uint32 interval);
JSValue js_actor_delay(JSContext *js, JSValue self, int argc, JSValue *argv);
JSValue js_actor_removetimer(JSContext *js, JSValue self, int argc, JSValue *argv);
@@ -79,5 +82,8 @@ void script_startup(prosperon_rt *rt);
void script_evalf(JSContext *js, const char *format, ...);
JSValue script_eval(JSContext *js, const char *file, const char *script);
void uncaught_exception(JSContext *js, JSValue v);
int actor_exists(char *id);
int prosperon_mount_core(void);
#endif

View File

@@ -370,9 +370,8 @@ static JSClassDef enet_peer_class = {
JSValue js_enet_resolve_hostname(JSContext *js, JSValue self, int argc, JSValue *argv)
{
// TODO: implement
char *hostname = JS_ToCString(js, argv[0]);
ENetAddress addr;
// Note: This function seems incomplete in the original - should it return something?
JS_FreeCString(js, hostname);
return JS_UNDEFINED;
}

View File

@@ -278,7 +278,7 @@ JSC_SSCALL(imgui_textbox,
ret = JS_DupValue(js,argv[1]);
)
JSC_SCALL(imgui_text, ImGui::Text(str) )
JSC_SCALL(imgui_text, ImGui::Text("%s", str) )
JSC_SCALL(imgui_button,
if (ImGui::Button(str))

View File

@@ -247,7 +247,7 @@ static JSValue js_tracy_image(JSContext *js, JSValue self, int argc, JSValue *ar
return JS_UNDEFINED;
}
#elifdef SOKOL_D3D11
#elif defined(SOKOL_D3D11)
#include <d3d11.h>
static int query_count = 64*1024;

View File

@@ -1,7 +1,6 @@
#include "quickjs.h"
#define WOTA_IMPLEMENTATION
#include "wota.h"
#include <stdlib.h>
typedef struct WotaEncodeContext {
JSContext *ctx;
@@ -89,7 +88,12 @@ static void encode_object_properties(WotaEncodeContext *enc, JSValueConst val, J
static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueConst holder, JSValueConst key)
{
JSContext *ctx = enc->ctx;
JSValue replaced = apply_replacer(enc, holder, key, val);
JSValue replaced;
if (!JS_IsUndefined(enc->replacer) && !JS_IsUndefined(key))
replaced = apply_replacer(enc, holder, key, val);
else
replaced = JS_DupValue(enc->ctx, val);
int tag = JS_VALUE_GET_TAG(replaced);
switch (tag) {
case JS_TAG_INT: {
@@ -177,12 +181,8 @@ static void wota_encode_value(WotaEncodeContext *enc, JSValueConst val, JSValueC
JS_FreeValue(ctx, replaced);
}
static char *decode_wota_value(JSContext *ctx, char *data_ptr, char *end_ptr, JSValue *out_val, JSValue holder, JSValue key, JSValue reviver)
static char *decode_wota_value(JSContext *ctx, char *data_ptr, JSValue *out_val, JSValue holder, JSValue key, JSValue reviver)
{
if ((end_ptr - data_ptr) < 8) {
*out_val = JS_UNDEFINED;
return data_ptr;
}
uint64_t first_word = *(uint64_t *)data_ptr;
int type = (int)(first_word & 0xffU);
switch (type) {
@@ -228,7 +228,7 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, char *end_ptr, JS
JSValue arr = JS_NewArray(ctx);
for (long long i = 0; i < c; i++) {
JSValue elem_val = JS_UNDEFINED;
data_ptr = decode_wota_value(ctx, data_ptr, end_ptr, &elem_val, arr, JS_NewInt32(ctx, i), reviver);
data_ptr = decode_wota_value(ctx, data_ptr, &elem_val, arr, JS_NewInt32(ctx, i), reviver);
JS_SetPropertyUint32(ctx, arr, i, elem_val);
}
*out_val = arr;
@@ -243,7 +243,7 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, char *end_ptr, JS
data_ptr = wota_read_text(&tkey, data_ptr);
JSValue prop_key = tkey ? JS_NewString(ctx, tkey) : JS_UNDEFINED;
JSValue sub_val = JS_UNDEFINED;
data_ptr = decode_wota_value(ctx, data_ptr, end_ptr, &sub_val, obj, prop_key, reviver);
data_ptr = decode_wota_value(ctx, data_ptr, &sub_val, obj, prop_key, reviver);
if (tkey) JS_SetPropertyStr(ctx, obj, tkey, sub_val);
else JS_FreeValue(ctx, sub_val);
JS_FreeValue(ctx, prop_key);
@@ -271,6 +271,36 @@ static char *decode_wota_value(JSContext *ctx, char *data_ptr, char *end_ptr, JS
return data_ptr;
}
void *value2wota(JSContext *ctx, JSValue v, JSValue replacer)
{
WotaEncodeContext enc_s, *enc = &enc_s;
enc->ctx = ctx;
enc->visited_stack = JS_NewArray(ctx);
enc->cycle = 0;
enc->replacer = replacer;
wota_buffer_init(&enc->wb, 16);
wota_encode_value(enc, v, JS_UNDEFINED, JS_UNDEFINED);
if (enc->cycle) {
JS_FreeValue(ctx, enc->visited_stack);
wota_buffer_free(&enc->wb);
return NULL;
}
JS_FreeValue(ctx, enc->visited_stack);
size_t total_bytes = enc->wb.size * sizeof(uint64_t);
void *wota = realloc(enc->wb.data, total_bytes);
return wota;
}
JSValue wota2value(JSContext *ctx, void *wota)
{
JSValue result = JS_UNDEFINED;
JSValue holder = JS_NewObject(ctx);
decode_wota_value(ctx, wota, &result, holder, JS_UNDEFINED, JS_UNDEFINED);
JS_FreeValue(ctx, holder);
return result;
}
static JSValue js_wota_encode(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
{
if (argc < 1) return JS_ThrowTypeError(ctx, "wota.encode requires at least 1 argument");
@@ -280,7 +310,7 @@ static JSValue js_wota_encode(JSContext *ctx, JSValueConst this_val, int argc, J
enc->cycle = 0;
enc->replacer = (argc > 1 && JS_IsFunction(ctx, argv[1])) ? argv[1] : JS_UNDEFINED;
wota_buffer_init(&enc->wb, 16);
wota_encode_value(enc, argv[0], JS_UNDEFINED, JS_NewString(ctx, ""));
wota_encode_value(enc, argv[0], JS_UNDEFINED, JS_UNDEFINED);
if (enc->cycle) {
JS_FreeValue(ctx, enc->visited_stack);
wota_buffer_free(&enc->wb);
@@ -301,10 +331,9 @@ static JSValue js_wota_decode(JSContext *ctx, JSValueConst this_val, int argc, J
if (!buf) return JS_UNDEFINED;
JSValue reviver = (argc > 1 && JS_IsFunction(ctx, argv[1])) ? argv[1] : JS_UNDEFINED;
char *data_ptr = (char *)buf;
char *end_ptr = data_ptr + len;
JSValue result = JS_UNDEFINED;
JSValue holder = JS_NewObject(ctx);
decode_wota_value(ctx, data_ptr, end_ptr, &result, holder, JS_NewString(ctx, ""), reviver);
decode_wota_value(ctx, data_ptr, &result, holder, JS_NewString(ctx, ""), reviver);
JS_FreeValue(ctx, holder);
return result;
}

View File

@@ -2,6 +2,7 @@
#define QJS_WOTA_H
#include <quickjs.h>
#include "wota.h"
JSValue js_wota_use(JSContext*);

View File

@@ -19,8 +19,6 @@ typedef struct viewstate {
extern viewstate globalview;
void render_init();
void capture_screen(int x, int y, int w, int h, const char *path);
void gif_rec_start(int w, int h, int cpf, int bitdepth);

View File

@@ -8,7 +8,7 @@ static sprite model = {
.color = {1, 1, 1, 1}
};
sprite *make_sprite()
sprite *make_sprite(void)
{
sprite *sprite = malloc(sizeof(*sprite));
*sprite = model;

View File

@@ -16,7 +16,7 @@ struct sprite{
typedef struct sprite sprite;
sprite *make_sprite();
sprite *make_sprite(void);
void sprite_free(JSRuntime *rt, sprite *sprite);
#endif

View File

@@ -553,8 +553,6 @@ static bool DrawNode(ImDrawList* drawList,
// test nested IO
drawList->ChannelsSetCurrent(1); // Background
const size_t InputsCount = nodeTemplate.mInputCount;
const size_t OutputsCount = nodeTemplate.mOutputCount;
/*
for (int i = 0; i < 2; i++)
@@ -647,7 +645,6 @@ static bool DrawNode(ImDrawList* drawList,
drawList->AddLine(progressLineA, progressLineB, 0xFF400000, 3.f);
drawList->AddLine(progressLineA, ImLerp(progressLineA, progressLineB, progress), 0xFFFF0000, 3.f);
}*/
ImVec2 imgPosMax = imgPos + ImVec2(imgSizeComp, imgSizeComp);
//ImVec2 imageSize = delegate->GetEvaluationSize(nodeIndex);
/*float imageRatio = 1.f;
@@ -828,7 +825,6 @@ void Show(Delegate& delegate, const Options& options, ViewState& viewState, bool
const ImVec2 windowPos = ImGui::GetCursorScreenPos();
const ImVec2 canvasSize = ImGui::GetContentRegionAvail();
const ImVec2 scrollRegionLocalPos(0, 0);
ImRect regionRect(windowPos, windowPos + canvasSize);

View File

@@ -101,16 +101,16 @@ par_shapes_mesh* par_shapes_create_parametric(par_shapes_fn, int slices,
// Generate points for a 20-sided polyhedron that fits in the unit sphere.
// Texture coordinates and normals are not generated.
par_shapes_mesh* par_shapes_create_icosahedron();
par_shapes_mesh* par_shapes_create_icosahedron(void);
// Generate points for a 12-sided polyhedron that fits in the unit sphere.
// Again, texture coordinates and normals are not generated.
par_shapes_mesh* par_shapes_create_dodecahedron();
par_shapes_mesh* par_shapes_create_dodecahedron(void);
// More platonic solids.
par_shapes_mesh* par_shapes_create_octahedron();
par_shapes_mesh* par_shapes_create_tetrahedron();
par_shapes_mesh* par_shapes_create_cube();
par_shapes_mesh* par_shapes_create_octahedron(void);
par_shapes_mesh* par_shapes_create_tetrahedron(void);
par_shapes_mesh* par_shapes_create_cube(void);
// Generate an orientable disk shape in 3-space. Does not include normals or
// texture coordinates.
@@ -118,7 +118,7 @@ par_shapes_mesh* par_shapes_create_disk(float radius, int slices,
float const* center, float const* normal);
// Create an empty shape. Useful for building scenes with merge_and_free.
par_shapes_mesh* par_shapes_create_empty();
par_shapes_mesh* par_shapes_create_empty(void);
// Generate a rock shape that sits on the Y=0 plane, and sinks into it a bit.
// This includes smooth normals but no texture coordinates. Each subdivision
@@ -751,7 +751,7 @@ par_shapes_mesh* par_shapes_create_disk(float radius, int slices,
return mesh;
}
par_shapes_mesh* par_shapes_create_empty()
par_shapes_mesh* par_shapes_create_empty(void)
{
return PAR_CALLOC(par_shapes_mesh, 1);
}
@@ -875,7 +875,7 @@ void par_shapes_invert(par_shapes_mesh* m, int face, int nfaces)
}
}
par_shapes_mesh* par_shapes_create_icosahedron()
par_shapes_mesh* par_shapes_create_icosahedron(void)
{
static float verts[] = {
0.000, 0.000, 1.000,
@@ -923,7 +923,7 @@ par_shapes_mesh* par_shapes_create_icosahedron()
return mesh;
}
par_shapes_mesh* par_shapes_create_dodecahedron()
par_shapes_mesh* par_shapes_create_dodecahedron(void)
{
static float verts[20 * 3] = {
0.607, 0.000, 0.795,
@@ -985,7 +985,7 @@ par_shapes_mesh* par_shapes_create_dodecahedron()
return mesh;
}
par_shapes_mesh* par_shapes_create_octahedron()
par_shapes_mesh* par_shapes_create_octahedron(void)
{
static float verts[6 * 3] = {
0.000, 0.000, 1.000,
@@ -1023,7 +1023,7 @@ par_shapes_mesh* par_shapes_create_octahedron()
return mesh;
}
par_shapes_mesh* par_shapes_create_tetrahedron()
par_shapes_mesh* par_shapes_create_tetrahedron(void)
{
static float verts[4 * 3] = {
0.000, 1.333, 0,
@@ -1055,7 +1055,7 @@ par_shapes_mesh* par_shapes_create_tetrahedron()
return mesh;
}
par_shapes_mesh* par_shapes_create_cube()
par_shapes_mesh* par_shapes_create_cube(void)
{
static float verts[8 * 3] = {
0, 0, 0, // 0
@@ -1141,7 +1141,7 @@ static par_shapes__rule* par_shapes__pick_rule(const char* name,
return rule;
}
static par_shapes_mesh* par_shapes__create_turtle()
static par_shapes_mesh* par_shapes__create_turtle(void)
{
const float xaxis[] = {1, 0, 0};
const float yaxis[] = {0, 1, 0};

View File

@@ -23,7 +23,7 @@ typedef struct transform {
void clean_all(JSContext *js);
transform *make_transform();
transform *make_transform(void);
void transform_free(JSRuntime *rt,transform *t);
void transform_apply(transform *t);

View File

@@ -309,8 +309,6 @@ char *wota_read_blob(long long *byte_len, char **blob, char *wota)
memset(*blob, 0, (size_t)(*byte_len));
uint64_t *data_words = p + 1;
long long bits_remaining = (long long)nbits;
size_t byte_i = 0;
int bit_in_byte = 0;
/* If nbits is multiple of 8, we can do a bulk copy in 64-bit chunks, then do leftover if any. */

12
tests/delay.js Normal file
View File

@@ -0,0 +1,12 @@
var count = 0
function loop()
{
count++;
console.log(`loop ${count}`);
if (count < 60)
$_.delay(loop, 0.01);
else
$_.stop()
}
$_.delay(loop,0.01)