a lot of stuff tbh

This commit is contained in:
alessandrobason 2022-08-19 17:09:27 +01:00
parent d80773bb00
commit 8ddd9186b8
42 changed files with 6463 additions and 1593 deletions

11
deprecated/coroutine.c Normal file
View file

@ -0,0 +1,11 @@
#include "coroutine.h"
coroutine_t coInit() {
return (coroutine_t) {
.state = 0
};
}
bool coIsDead(coroutine_t co) {
return co.state == -1;
}

133
deprecated/coroutine.h Normal file
View file

@ -0,0 +1,133 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h> // bool
#include <string.h> // memset
#include "tracelog.h" // fatal
// heavily inspired by https://gist.github.com/Enichan/5f01140530ff0133fde19c9549a2a973
#if 0
// Usage example:
typedef struct {
int result;
coroutine_t co;
} co_int_t;
bool coVoid(co_void_t *co) {
costate(co_nostate);
coroutine({
printf("hello"); yield();
printf("world"); yield();
printf("how"); yield();
printf("is"); yield();
printf("it"); yield();
printf("going?\n");
});
}
bool countToTen(co_int_t *co) {
costate(int i; int ii;);
coroutine({
for(self.i = 0; self.i < 10; ++self.i) {
self.ii += self.i;
yieldVal(self.ii);
}
});
}
int main() {
co_void_t covoid = {0};
while(coVoid(&covoid)) {
printf(" ");
}
co_int_t coint;
coint.co = coInit();
while(countToTen(&coint)) {
printf("%d ", coint.result);
}
printf("\n");
// reset coroutine for next call
coint.co = coInit();
while(countToTen(&coint)) {
printf("%d ", coint.result);
}
printf("\n");
}
#endif
typedef struct {
int state;
} coroutine_t;
typedef struct {
coroutine_t co;
} co_void_t;
coroutine_t coInit();
bool coIsDead(coroutine_t co);
#define COVAR co
#define COSELF self
#define costate(...) \
typedef struct { bool init; __VA_ARGS__ } COSTATE; \
static COSTATE self = {0}
#define co_nostate { char __dummy__; }
#define yieldBreak() \
COVAR->co.state = -1; \
self.init = false; \
return false;
#define coroutine(...) \
if(!self.init) { \
if(COVAR->co.state != 0) { \
fatal("coroutine not initialized in %s:%d,\n" \
"did you forget to do '= {0};'?", \
__FILE__, __LINE__); \
} \
memset(&self, 0, sizeof(self)); \
self.init = true; \
} \
switch(COVAR->co.state) { \
case 0:; \
__VA_ARGS__ \
} \
yieldBreak();
#define yield() _yield(__COUNTER__)
#define _yield(count) \
do { \
COVAR->co.state = count; \
return true; \
case count:; \
} while(0);
#define yieldVal(v) _yieldVal(v, __COUNTER__)
#define _yieldVal(v, count) \
do { \
COVAR->co.state = count; \
COVAR->result = v; \
return true; \
case count:; \
} while(0);
// increment __COUNTER__ past 0 so we don't get double case errors
#define CONCAT_IMPL(x, y) x##y
#define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y)
#define __INC_COUNTER int MACRO_CONCAT(__counter_tmp_, __COUNTER__)
__INC_COUNTER;
#undef CONCAT_IMPL
#undef MACRO_CONCAT
#undef __INC_COUNTER
#ifdef __cplusplus
} // extern "C"
#endif

295
deprecated/dirwatch.c Normal file
View file

@ -0,0 +1,295 @@
#include "dirwatch.h"
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include "tracelog.h"
#ifdef _WIN32
#include "win32_slim.h"
#include "str.h"
typedef struct {
const char *path;
dirwatch_cb_t on_event;
BOOL should_continue;
HANDLE stop_event;
} __dirwatch_internal_t;
static int watchDirThread(void *cdata) {
__dirwatch_internal_t *desc = (__dirwatch_internal_t*)cdata;
// stop_event is called from another thread when watchDirThread should exit
desc->stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
HANDLE file = CreateFile(
desc->path,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL
);
assert(file != INVALID_HANDLE_VALUE);
OVERLAPPED overlapped = {0};
overlapped.hEvent = CreateEvent(NULL, FALSE, 0, NULL);
uint8_t change_buf[1024];
BOOL success = ReadDirectoryChangesW(
file, change_buf, sizeof(change_buf), TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE,
NULL, &overlapped, NULL
);
assert(success);
HANDLE events[2] = {
overlapped.hEvent,
desc->stop_event
};
WCHAR old_name[MAX_PATH];
dirwatch_file_t data = {0};
// if the variable is 32bit aligned, a read/write is already atomice
// https://docs.microsoft.com/en-us/windows/win32/sync/interlocked-variable-access
while(desc->should_continue) {
DWORD result = WaitForMultipleObjects(2, events, FALSE, INFINITE);
if(result == WAIT_OBJECT_0) {
DWORD bytes_transferred;
GetOverlappedResult(file, &overlapped, &bytes_transferred, FALSE);
FILE_NOTIFY_INFORMATION *event = (FILE_NOTIFY_INFORMATION*)change_buf;
for(;;) {
DWORD name_len = event->FileNameLength / sizeof(wchar_t);
switch(event->Action) {
case FILE_ACTION_ADDED:
data.name = strFromWCHAR(event->FileName, name_len).buf;
data.oldname = NULL;
desc->on_event(desc->path, DIRWATCH_FILE_ADDED, data);
break;
case FILE_ACTION_REMOVED:
data.name = strFromWCHAR(event->FileName, name_len).buf;
data.oldname = NULL;
desc->on_event(desc->path, DIRWATCH_FILE_REMOVED, data);
break;
case FILE_ACTION_RENAMED_OLD_NAME:
memcpy(old_name, event->FileName, event->FileNameLength);
old_name[event->FileNameLength] = '\0';
break;
case FILE_ACTION_RENAMED_NEW_NAME:
data.name = strFromWCHAR(event->FileName, name_len).buf;
data.oldname = strFromWCHAR(old_name, 0).buf;
desc->on_event(desc->path, DIRWATCH_FILE_RENAMED, data);
break;
}
if(data.name) free(data.name);
if(data.oldname) free(data.oldname);
data = (dirwatch_file_t){0};
if(event->NextEntryOffset) {
*((uint8_t**)&event) += event->NextEntryOffset;
}
else {
break;
}
}
success = ReadDirectoryChangesW(
file, change_buf, sizeof(change_buf), TRUE,
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_LAST_WRITE,
NULL, &overlapped, NULL
);
assert(success);
}
// stop_event
else if(result == WAIT_OBJECT_0 + 1) {
warn("stopping");
break;
}
}
return 0;
}
dirwatch_t watchDir(dirwatch_desc_t desc) {
dirwatch_t dir = {0};
__dirwatch_internal_t *opts = HeapAlloc(
GetProcessHeap(),
0,
sizeof(__dirwatch_internal_t)
);
opts->path = desc.path;
opts->on_event = desc.on_event;
opts->should_continue = true;
dir.desc = (dirwatch_desc_t *)opts;
dir.handle = thrCreate(watchDirThread, (void *)dir.desc);
if(thrValid(dir.handle)) {
info("watching %s", desc.path);
}
return dir;
}
void waitForWatchDir(dirwatch_t *ctx) {
if(!thrValid(ctx->handle)) {
err("not valid");
return;
}
if(!thrJoin(ctx->handle, NULL)) {
err("dirwatch: couldn't wait for thread");
}
info("waited");
HeapFree(GetProcessHeap(), 0, ctx->desc);
}
void stopWatchDir(dirwatch_t *ctx, bool immediately) {
(void)immediately;
__dirwatch_internal_t *opts = (__dirwatch_internal_t *)ctx->desc;
opts->should_continue = false;
if(immediately) {
if(!SetEvent(opts->stop_event)) {
err("couldn't signal event stop_event: %d", GetLastError());
}
}
if(!thrJoin(ctx->handle, NULL)) {
err("dirwatch: couldn't wait for thread");
}
HeapFree(GetProcessHeap(), 0, ctx->desc);
}
#else
#include <sys/inotify.h>
#include <unistd.h> // read
#include <string.h>
#include <errno.h>
#include <linux/limits.h> // MAX_PATH
#include <stdatomic.h>
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
#define ERROR(str) { err(str ": %s", strerror(errno)); goto error; }
typedef struct {
const char *path;
dirwatch_cb_t on_event;
atomic_bool should_continue;
int fd;
int wd;
} __dirwatch_internal_t;
static int watchDirThread(void *cdata) {
__dirwatch_internal_t *desc = (__dirwatch_internal_t *)cdata;
info("watching %s", desc->path);
int length/*, fd, wd*/;
char buffer[BUF_LEN];
desc->fd = inotify_init();
if(desc->fd < 0) {
ERROR("inotify_init failed");
}
desc->wd = inotify_add_watch(desc->fd, desc->path, IN_MOVE | IN_CREATE | IN_DELETE);
char old_path[PATH_MAX] = {0};
dirwatch_file_t data = {0};
while(desc->should_continue) {
length = (int)read(desc->fd, buffer, BUF_LEN);
if(length < 0) {
ERROR("couldn't read");
}
for(int i = 0; i < length;) {
struct inotify_event *event = (struct inotify_event *) &buffer[i];
if(event->len) {
uint32_t e = event->mask;
// bool is_dir = e & IN_ISDIR;
if(e & IN_CREATE) {
data.name = event->name;
desc->on_event(desc->path, DIRWATCH_FILE_ADDED, data);
}
else if(e & IN_DELETE) {
data.name = event->name;
desc->on_event(desc->path, DIRWATCH_FILE_REMOVED, data);
}
else if(e & IN_MOVED_FROM) {
memcpy(old_path, event->name, event->len);
old_path[event->len] = '\0';
}
else if(e & IN_MOVED_TO) {
data.oldname = old_path;
data.name = event->name;
desc->on_event(desc->path, DIRWATCH_FILE_RENAMED, data);
}
}
i += EVENT_SIZE + event->len;
}
}
inotify_rm_watch(desc->fd, desc->wd);
close(desc->fd);
return 0;
error:
return 1;
}
dirwatch_t watchDir(dirwatch_desc_t desc) {
dirwatch_t dir = {0};
__dirwatch_internal_t *opts = malloc(sizeof(__dirwatch_internal_t));
opts->path = desc.path;
opts->on_event = desc.on_event;
opts->fd = 0;
opts->wd = 0;
opts->should_continue = true;
dir.desc = (dirwatch_desc_t *)opts;
dir.handle = thrCreate(watchDirThread, opts);
return dir;
}
void waitForWatchDir(dirwatch_t *ctx) {
thrJoin(ctx->handle, NULL);
free(ctx->desc);
}
void stopWatchDir(dirwatch_t *ctx, bool immediately) {
__dirwatch_internal_t *opts = (__dirwatch_internal_t *)ctx->desc;
opts->should_continue = false;
// this one might get called in the thread first, but it doesn't matter
if(immediately) {
inotify_rm_watch(opts->fd, opts->wd);
close(opts->fd);
}
thrJoin(ctx->handle, NULL);
free(opts);
}
#endif

67
deprecated/dirwatch.h Normal file
View file

@ -0,0 +1,67 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/*
* Basic usage:
*
* // this function will be called from another thread every time
* // something happens to 'path'
* void onEvent(const char *path, int action, dirwatch_file_t file) {
* switch(action) {
* case DIRWATCH_FILE_ADDED: [do something] break;
* case DIRWATCH_FILE_REMOVED: [do something] break;
* case DIRWATCH_FILE_RENAMED: [do something] break;
* }
* }
*
* int main() {
* dirwatch_t dir = watchDir((dirwatch_desc_t){
* .dirname = "watch/",
* .on_event = onEvent
* });
*
* waitForWatchDir(&dir);
* }
*/
#include <stdbool.h>
#include "cthreads.h"
enum {
DIRWATCH_FILE_ADDED,
DIRWATCH_FILE_REMOVED,
DIRWATCH_FILE_RENAMED,
};
typedef struct {
char *name;
char *oldname;
} dirwatch_file_t;
typedef void (*dirwatch_cb_t)(const char *path, int action, dirwatch_file_t data);
typedef struct {
const char *path;
dirwatch_cb_t on_event;
} dirwatch_desc_t;
typedef struct {
cthread_t handle;
dirwatch_desc_t *desc;
} dirwatch_t;
// Creates a thread and starts watching the folder specified by desc
// if any action happend on_event will be called from this thread
dirwatch_t watchDir(dirwatch_desc_t desc);
// waits forever
void waitForWatchDir(dirwatch_t *ctx);
// stops dirwatch thread, if immediately is true, it will try to close it right away
// otherwise it might wait for one last event
void stopWatchDir(dirwatch_t *ctx, bool immediately);
#ifdef __cplusplus
} // extern "C"
#endif

134
deprecated/fs.c Normal file
View file

@ -0,0 +1,134 @@
#include "fs.h"
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "tracelog.h"
#ifdef _WIN32
#include "win32_slim.h"
#include <sys/stat.h>
static fsmode_t _modeToType(unsigned int mode) {
switch(mode & _S_IFMT) {
case _S_IFDIR: return FS_MODE_DIR;
case _S_IFCHR: return FS_MODE_CHARACTER_DEVICE;
case _S_IFREG: return FS_MODE_FILE;
case _S_IFIFO: return FS_MODE_FIFO;
default: return FS_MODE_UKNOWN;
}
}
fs_stat_t fsStat(file_t fp) {
TCHAR path[MAX_PATH];
GetFinalPathNameByHandle(
(HANDLE)fp.handle,
path,
MAX_PATH,
0
);
struct stat statbuf;
int res = stat(path, &statbuf);
if(res == 0) {
return (fs_stat_t) {
.type = _modeToType(statbuf.st_mode),
.size = statbuf.st_size,
.last_access = statbuf.st_atime,
.last_modif = statbuf.st_mtime
};
}
else {
return (fs_stat_t) { 0 };
}
}
fs_time_t fsAsTime(int64_t timer) {
struct tm t;
errno_t error = localtime_s(&t, &timer);
if(error == 0) {
return (fs_time_t) {
.year = t.tm_year + 1900,
.month = t.tm_mon + 1,
.day = t.tm_mday,
.hour = t.tm_hour,
.minutes = t.tm_min,
.seconds = t.tm_sec,
.daylight_saving = t.tm_isdst > 0
};
}
else {
char buf[128];
strerror_s(buf, sizeof(buf), error);
err("%s", buf);
return (fs_time_t) { 0 };
}
}
bool fsIsDir(const char *path) {
DWORD attr = GetFileAttributes(path);
return attr != INVALID_FILE_ATTRIBUTES &&
attr & FILE_ATTRIBUTE_DIRECTORY;
}
#else
#include <sys/stat.h>
static fsmode_t _modeToType(unsigned int mode) {
switch(mode & __S_IFMT) {
case __S_IFDIR: return FS_MODE_DIR;
case __S_IFCHR: return FS_MODE_CHARACTER_DEVICE;
case __S_IFREG: return FS_MODE_FILE;
case __S_IFIFO: return FS_MODE_FIFO;
default: return FS_MODE_UKNOWN;
}
}
fs_stat_t fsStat(file_t fp) {
int fd = fileno((FILE*)fp);
struct stat statbuf;
int res = fstat(fd, &statbuf);
if(res == 0) {
return (fs_stat_t) {
.type = _modeToType(statbuf.st_mode),
.size = (uint64_t)statbuf.st_size,
.last_access = statbuf.st_atime,
.last_modif = statbuf.st_mtime
};
}
else {
return (fs_stat_t) { 0 };
}
}
fs_time_t fsAsTime(int64_t timer) {
struct tm *t = localtime(&timer);
if(t) {
return (fs_time_t) {
.year = t->tm_year + 1900,
.month = t->tm_mon + 1,
.day = t->tm_mday,
.hour = t->tm_hour,
.minutes = t->tm_min,
.seconds = t->tm_sec,
.daylight_saving = t->tm_isdst > 0
};
}
else {
err("%s", strerror(errno));
return (fs_time_t) { 0 };
}
}
bool fsIsDir(const char *path) {
struct stat statbuf;
return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode);
}
#endif

44
deprecated/fs.h Normal file
View file

@ -0,0 +1,44 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "file.h"
typedef enum {
FS_MODE_FILE,
FS_MODE_DIR,
FS_MODE_CHARACTER_DEVICE,
FS_MODE_FIFO,
FS_MODE_UKNOWN,
} fsmode_t;
typedef struct {
fsmode_t type;
uint64_t size;
int64_t last_access;
int64_t last_modif;
} fs_stat_t;
typedef struct {
int year;
int month;
int day;
int hour;
int minutes;
int seconds;
bool daylight_saving;
} fs_time_t;
fs_stat_t fsStat(file_t fp);
fs_time_t fsAsTime(int64_t time);
bool fsIsDir(const char *path);
#ifdef __cplusplus
} // extern "C"
#endif