Compare commits

..

No commits in common. "26215541657492191282cacad8a4460b6edd072d" and "af1244b82942384a9721b8f42598627112772274" have entirely different histories.

15 changed files with 188 additions and 488 deletions

15
TODO.md
View File

@ -1,10 +1,6 @@
# Parity with Vanilla OC (only the stuff that makes sense for an emulator)
- make the `unicode` library in testLuaArch support invalid UTF-8 (WHY IS IT OK WITH THAT)
- in-memory version of `filesystem`
- complete the GPU implementation (screen buffers and missing methods)
- complete the screen implementation (bunch of missing methods)
- support invalid UTF-8 for GPU set and fill, which should pretend the byte value is the codepoint.
- in-memory version of `filesystem` and `drive`
- `hologram` component
- `computer` component
- `modem` component
@ -15,10 +11,14 @@
- `disk_drive` component
- `computer.getDeviceInfo()`, and subsequently, component device information
- `computer.beep(frequency?: number, duration?: number, volume?: number)`, frequency between 20 and 2000 Hz, duration up to 5 seconds, volume from 0 to 1.
- complete the GPU implementation (screen buffers and missing methods)
- complete the screen implementation (bunch of missing methods)
- support invalid UTF-8 for GPU set and fill, which should pretend the byte value is the codepoint.
# Bugfixes
- Rework filesystem component to pre-process paths to ensure proper sandboxing and not allow arbitrary remote file access
- Ensure the recursive locks are used correctly to prevent race conditions
- Do a huge audit at some point
# The extra components
@ -35,8 +35,11 @@
- `tape_drive` component, compatible with Computronics, except maybe with proper seek times and support for multiple tapes
- `cd_reader` and `cd_writer` components, to work with CDs
# API changes
- move controls into the component instances instead of using getters, to boost performance
# Internal changes
- rework some interfaces to account for possibility of errors
- use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging
- setup an extensive testing system to find bugs easier

View File

@ -26,10 +26,8 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module {
"src/unicode.c",
// components
"src/components/eeprom.c",
"src/components/volatileEeprom.c",
"src/components/filesystem.c",
"src/components/drive.c",
"src/components/volatileDrive.c",
"src/components/screen.c",
"src/components/gpu.c",
"src/components/keyboard.c",
@ -70,7 +68,7 @@ fn compileTheRightLua(b: *std.Build, target: std.Build.ResolvedTarget, version:
const c = b.addObject(.{
.name = "lua",
.link_libc = true,
.optimize = .ReleaseFast,
.optimize = .ReleaseSafe,
.target = target,
});

View File

@ -1,58 +1,28 @@
#include "../neonucleus.h"
typedef struct nn_drive {
nn_refc refc;
nn_guard *lock;
nn_Context ctx;
typedef struct nni_drive {
nn_drive *funcs;
nn_size_t currentSector;
nn_driveTable table;
nn_driveControl ctrl;
} nn_drive;
} nni_drive;
nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control) {
nn_drive *d = nn_alloc(&context->allocator, sizeof(nn_drive));
if(d == NULL) return NULL;
d->lock = nn_newGuard(context);
if(d->lock == NULL) {
nn_dealloc(&context->allocator, d, sizeof(nn_drive));
return NULL;
}
d->refc = 1;
d->table = table;
d->ctrl = control;
d->currentSector = 0;
d->ctx = *context;
return d;
}
void nn_drive_destroy(void *_, nn_component *component, nni_drive *drive) {
if(!nn_decRef(&drive->funcs->refc)) return;
nn_guard *nn_getDriveLock(nn_drive *drive) {
return drive->lock;
}
void nn_retainDrive(nn_drive *drive) {
nn_incRef(&drive->refc);
}
nn_bool_t nn_destroyDrive(nn_drive *drive) {
if(!nn_decRef(&drive->refc)) return false;
if(drive->table.deinit != NULL) {
drive->table.deinit(drive->table.userdata);
if(drive->funcs->deinit != NULL) {
drive->funcs->deinit(component, drive->funcs->userdata);
}
nn_Context ctx = drive->ctx;
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(nn_getComputerOfComponent(component)));
nn_deleteGuard(&ctx, drive->lock);
nn_dealloc(&ctx.allocator, drive, sizeof(nn_drive));
return true;
nn_dealloc(alloc, drive, sizeof(nni_drive));
}
void nn_drive_destroy(void *_, nn_component *component, nn_drive *drive) {
nn_destroyDrive(drive);
nn_driveControl nn_drive_getControl(nn_component *component, nni_drive *drive) {
return drive->funcs->control(component, drive->funcs->userdata);
}
void nni_drive_readCost(nn_component *component, nn_drive *drive) {
nn_driveControl ctrl = drive->ctrl;
void nni_drive_readCost(nn_component *component, nni_drive *drive) {
nn_driveControl ctrl = nn_drive_getControl(component, drive);
nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, 1, ctrl.readSectorsPerTick);
@ -60,8 +30,8 @@ void nni_drive_readCost(nn_component *component, nn_drive *drive) {
nn_removeEnergy(computer, ctrl.readEnergyPerSector);
}
void nni_drive_writeCost(nn_component *component, nn_drive *drive) {
nn_driveControl ctrl = drive->ctrl;
void nni_drive_writeCost(nn_component *component, nni_drive *drive) {
nn_driveControl ctrl = nn_drive_getControl(component, drive);
nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, 1, ctrl.writeSectorsPerTick);
@ -69,19 +39,19 @@ void nni_drive_writeCost(nn_component *component, nn_drive *drive) {
nn_removeEnergy(computer, ctrl.writeEnergyPerSector);
}
void nni_drive_seekTo(nn_component *component, nn_drive *drive, nn_size_t sector) {
void nni_drive_seekTo(nn_component *component, nni_drive *drive, nn_size_t sector) {
sector = sector - 1; // switch to 0 to N-1 sector addressing,
// which is much nicer to do math with
// and Lua made a big oopsie.
nn_size_t old = drive->currentSector;
nn_driveControl ctrl = drive->ctrl;
nn_driveControl ctrl = nn_drive_getControl(component, drive);
if(ctrl.seekSectorsPerTick == 0) return; // seek latency disabled
nn_computer *computer = nn_getComputerOfComponent(component);
// Compute important constants
nn_size_t sectorSize = drive->table.sectorSize;
nn_size_t platterCount = drive->table.platterCount;
nn_size_t capacity = drive->table.capacity;
nn_size_t sectorSize = drive->funcs->getSectorSize(component, drive->funcs->userdata);
nn_size_t platterCount = drive->funcs->getPlatterCount(component, drive->funcs->userdata);
nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata);
nn_size_t sectorsPerPlatter = (capacity / sectorSize) / platterCount;
@ -113,19 +83,17 @@ void nni_drive_seekTo(nn_component *component, nn_drive *drive, nn_size_t sector
nn_removeEnergy(computer, ctrl.motorEnergyPerSector * moved);
}
void nn_drive_getLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_getLabel(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
char buf[NN_LABEL_SIZE];
nn_size_t l = NN_LABEL_SIZE;
nn_lock(&drive->ctx, drive->lock);
drive->table.getLabel(drive->table.userdata, buf, &l);
nn_unlock(&drive->ctx, drive->lock);
drive->funcs->getLabel(component, drive->funcs->userdata, buf, &l);
if(l == 0) {
nn_return(computer, nn_values_nil());
} else {
nn_return_string(computer, buf, l);
}
}
void nn_drive_setLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_setLabel(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t l = 0;
nn_value label = nn_getArgument(computer, 0);
const char *buf = nn_toString(label, &l);
@ -133,42 +101,38 @@ void nn_drive_setLabel(nn_drive *drive, void *_, nn_component *component, nn_com
nn_setCError(computer, "bad label (string expected)");
return;
}
nn_lock(&drive->ctx, drive->lock);
l = drive->table.setLabel(drive->table.userdata, buf, l);
nn_unlock(&drive->ctx, drive->lock);
l = drive->funcs->setLabel(component, drive->funcs->userdata, buf, l);
nn_return_string(computer, buf, l);
}
void nn_drive_getSectorSize(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t sector_size = drive->table.sectorSize;
void nn_drive_getSectorSize(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
nn_return(computer, nn_values_integer(sector_size));
}
void nn_drive_getPlatterCount(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t platter_count = drive->table.platterCount;
void nn_drive_getPlatterCount(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t platter_count = drive->funcs->getPlatterCount(component, drive->funcs->userdata);
nn_return(computer, nn_values_integer(platter_count));
}
void nn_drive_getCapacity(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t capacity = drive->table.capacity;
void nn_drive_getCapacity(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata);
nn_return(computer, nn_values_integer(capacity));
}
void nn_drive_readSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_readSector(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value sectorValue = nn_getArgument(computer, 0);
int sector = nn_toInt(sectorValue);
nn_size_t sector_size = drive->table.sectorSize;
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
// we leave the +1 intentionally to compare the end of the real sector
if (sector < 1 || (sector * sector_size > drive->table.capacity)) {
if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) {
nn_setCError(computer, "bad argument #1 (sector out of range)");
return;
}
char buf[sector_size];
nn_lock(&drive->ctx, drive->lock);
drive->table.readSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf);
nn_return_string(computer, buf, sector_size);
}
void nn_drive_writeSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_writeSector(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value sectorValue = nn_getArgument(computer, 0);
int sector = nn_toInt(sectorValue);
nn_size_t sector_size = drive->table.sectorSize;
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
nn_value bufValue = nn_getArgument(computer, 1);
nn_size_t buf_size = 0;
@ -178,40 +142,34 @@ void nn_drive_writeSector(nn_drive *drive, void *_, nn_component *component, nn_
return;
}
// we leave the +1 intentionally to compare the end of the real sector
if (sector < 1 || (sector * sector_size > drive->table.capacity)) {
if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) {
nn_setCError(computer, "bad argument #1 (sector out of range)");
return;
}
nn_lock(&drive->ctx, drive->lock);
drive->table.writeSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
nn_return_boolean(computer, true);
drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf);
}
void nn_drive_readByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_readByte(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value offsetValue = nn_getArgument(computer, 0);
nn_size_t disk_offset = nn_toInt(offsetValue) - 1;
nn_size_t sector_size = drive->table.sectorSize;
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
int sector = (disk_offset / sector_size) + 1;
nn_size_t sector_offset = disk_offset % sector_size;
if (disk_offset >= drive->table.capacity) {
if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) {
nn_setCError(computer, "bad argument #1 (index out of range)");
return;
}
char buf[sector_size];
nn_lock(&drive->ctx, drive->lock);
drive->table.readSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf);
nn_return(computer, nn_values_integer(buf[sector_offset]));
}
void nn_drive_writeByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_writeByte(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value offsetValue = nn_getArgument(computer, 0);
nn_value writeValue = nn_getArgument(computer, 1);
nn_size_t disk_offset = nn_toInt(offsetValue) - 1;
nn_intptr_t write = nn_toInt(writeValue);
nn_size_t sector_size = drive->table.sectorSize;
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
int sector = (disk_offset / sector_size) + 1;
nn_size_t sector_offset = disk_offset % sector_size;
@ -219,20 +177,16 @@ void nn_drive_writeByte(nn_drive *drive, void *_, nn_component *component, nn_co
nn_setCError(computer, "bad argument #2 (byte out of range)");
return;
}
if (disk_offset >= drive->table.capacity) {
if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) {
nn_setCError(computer, "bad argument #1 (index out of range)");
return;
}
nn_lock(&drive->ctx, drive->lock);
char buf[sector_size];
drive->table.readSector(drive->table.userdata, sector, buf);
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf);
buf[sector_offset] = write;
drive->table.writeSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
nn_return_boolean(computer, true);
drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf);
}
void nn_loadDriveTable(nn_universe *universe) {
@ -251,7 +205,15 @@ void nn_loadDriveTable(nn_universe *universe) {
}
nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive) {
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
nni_drive *d = nn_alloc(alloc, sizeof(nni_drive));
d->currentSector = 0;
d->funcs = drive;
nn_componentTable *driveTable = nn_queryUserdata(nn_getUniverse(computer), "NN:DRIVE");
return nn_newComponent(computer, address, slot, driveTable, drive);
nn_component *c = nn_newComponent(computer, address, slot, driveTable, drive);
if(c == NULL) {
nn_dealloc(alloc, d, sizeof(nni_drive));
}
return c;
}

View File

@ -142,11 +142,6 @@ void nn_eeprom_set(nn_eeprom *eeprom, void *_, nn_component *component, nn_compu
}
}
nn_lock(&eeprom->ctx, eeprom->lock);
if(eeprom->table.isReadonly(eeprom->table.userdata)) {
nn_unlock(&eeprom->ctx, eeprom->lock);
nn_setCError(computer, "readonly");
return;
}
eeprom->table.set(eeprom->table.userdata, buf, len);
nn_unlock(&eeprom->ctx, eeprom->lock);
@ -192,11 +187,6 @@ void nn_eeprom_setData(nn_eeprom *eeprom, void *_, nn_component *component, nn_c
return;
}
nn_lock(&eeprom->ctx, eeprom->lock);
if(eeprom->table.isReadonly(eeprom->table.userdata)) {
nn_unlock(&eeprom->ctx, eeprom->lock);
nn_setCError(computer, "readonly");
return;
}
eeprom->table.setData(eeprom->table.userdata, buf, len);
nn_unlock(&eeprom->ctx, eeprom->lock);
@ -265,7 +255,7 @@ void nn_loadEepromTable(nn_universe *universe) {
nn_defineMethod(eepromTable, "getChecksum", true, (void *)nn_eeprom_getChecksum, NULL, "getChecksum(): string - Returns a checksum of the data on the EEPROM.");
}
nn_component *nn_addEEPROM(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom) {
nn_component *nn_addEeprom(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom) {
nn_componentTable *eepromTable = nn_queryUserdata(nn_getUniverse(computer), "NN:EEPROM");
return nn_newComponent(computer, address, slot, eepromTable, eeprom);

View File

@ -58,28 +58,19 @@ nn_bool_t nn_destroyFilesystem(nn_filesystem *fs) {
}
nn_size_t nn_fs_getSpaceUsed(nn_filesystem *fs) {
nn_lock(&fs->ctx, fs->lock);
if(fs->spaceUsedCache != 0) {
nn_unlock(&fs->ctx, fs->lock);
return fs->spaceUsedCache;
}
if(fs->spaceUsedCache != 0) return fs->spaceUsedCache;
nn_size_t spaceUsed = fs->table.spaceUsed(fs->table.userdata);
fs->spaceUsedCache = spaceUsed;
nn_unlock(&fs->ctx, fs->lock);
return spaceUsed;
}
void nn_fs_invalidateSpaceUsed(nn_filesystem *fs) {
nn_lock(&fs->ctx, fs->lock);
fs->spaceUsedCache = 0;
nn_unlock(&fs->ctx, fs->lock);
}
nn_size_t nn_fs_getSpaceRemaining(nn_filesystem *fs) {
nn_lock(&fs->ctx, fs->lock);
nn_size_t used = nn_fs_getSpaceUsed(fs);
nn_size_t total = fs->table.spaceTotal;
nn_unlock(&fs->ctx, fs->lock);
return total - used;
}
@ -87,9 +78,7 @@ void *nn_fs_unwrapFD(nn_filesystem *fs, nn_size_t fd) {
if(fd >= NN_MAX_OPEN_FILES) {
return NULL;
}
nn_lock(&fs->ctx, fs->lock);
void *file = fs->files[fd];
nn_unlock(&fs->ctx, fs->lock);
if(file == NULL) {
return NULL;
}
@ -145,9 +134,7 @@ void nn_fs_createCost(nn_filesystem *fs, nn_size_t count, nn_component *componen
void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
char buf[NN_LABEL_SIZE];
nn_size_t l = NN_LABEL_SIZE;
nn_lock(&fs->ctx, fs->lock);
fs->table.getLabel(fs->table.userdata, buf, &l);
nn_unlock(&fs->ctx, fs->lock);
if(l == 0) {
nn_return(computer, nn_values_nil());
} else {
@ -165,9 +152,7 @@ void nn_fs_setLabel(nn_filesystem *fs, void *_, nn_component *component, nn_comp
nn_setCError(computer, "bad label (string expected)");
return;
}
nn_lock(&fs->ctx, fs->lock);
l = fs->table.setLabel(fs->table.userdata, buf, l);
nn_unlock(&fs->ctx, fs->lock);
nn_return_string(computer, buf, l);
nn_fs_writeCost(fs, l, component);
@ -183,9 +168,7 @@ void nn_fs_spaceTotal(nn_filesystem *fs, void *_, nn_component *component, nn_co
}
void nn_fs_isReadOnly(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.isReadOnly(fs->table.userdata));
nn_unlock(&fs->ctx, fs->lock);
}
void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -200,9 +183,7 @@ void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_size_t byteSize = fs->table.size(fs->table.userdata, path);
nn_unlock(&fs->ctx, fs->lock);
nn_return(computer, nn_values_integer(byteSize));
}
@ -219,9 +200,7 @@ void nn_fs_remove(nn_filesystem *fs, void *_, nn_component *component, nn_comput
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_size_t removed = fs->table.remove(fs->table.userdata, path);
nn_unlock(&fs->ctx, fs->lock);
nn_return_boolean(computer, removed > 0);
nn_fs_removeCost(fs, removed, component);
@ -239,9 +218,7 @@ void nn_fs_lastModified(nn_filesystem *fs, void *_, nn_component *component, nn_
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_size_t t = fs->table.lastModified(fs->table.userdata, path);
nn_unlock(&fs->ctx, fs->lock);
// OpenOS does BULLSHIT with this thing, dividing it by 1000 and expecting it to be
// fucking usable as a date, meaning it needs to be an int.
@ -274,9 +251,7 @@ void nn_fs_rename(nn_filesystem *fs, void *_, nn_component *component, nn_comput
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_size_t movedCount = fs->table.rename(fs->table.userdata, from, to);
nn_unlock(&fs->ctx, fs->lock);
nn_return(computer, nn_values_boolean(movedCount > 0));
nn_fs_removeCost(fs, movedCount, component);
@ -295,9 +270,7 @@ void nn_fs_exists(nn_filesystem *fs, void *_, nn_component *component, nn_comput
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.exists(fs->table.userdata, path));
nn_unlock(&fs->ctx, fs->lock);
}
void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -312,9 +285,7 @@ void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_c
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, path));
nn_unlock(&fs->ctx, fs->lock);
}
void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -329,9 +300,7 @@ void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, path));
nn_unlock(&fs->ctx, fs->lock);
nn_fs_createCost(fs, 1, component);
}
@ -351,9 +320,7 @@ void nn_fs_list(nn_filesystem *fs, void *_, nn_component *component, nn_computer
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
nn_size_t fileCount = 0;
nn_lock(&fs->ctx, fs->lock);
char **files = fs->table.list(alloc, fs->table.userdata, path, &fileCount);
nn_unlock(&fs->ctx, fs->lock);
if(files != NULL) {
// operation succeeded
@ -385,7 +352,6 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer
mode = "r";
}
nn_lock(&fs->ctx, fs->lock);
// technically wrongfully
if(!fs->table.exists(fs->table.userdata, path)) {
nn_fs_createCost(fs, 1, component);
@ -395,18 +361,15 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer
while(fs->files[fd] != NULL) {
fd++;
if(fd == NN_MAX_OPEN_FILES) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "too many open files");
return;
}
}
void *file = fs->table.open(fs->table.userdata, path, mode);
if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "no such file or directory");
return;
}
nn_unlock(&fs->ctx, fs->lock);
fs->files[fd] = file;
nn_return(computer, nn_values_integer(fd));
}
@ -420,12 +383,10 @@ void nn_fs_close(nn_filesystem *fs, void *_, nn_component *component, nn_compute
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_bool_t closed = fs->table.close(fs->table.userdata, file);
if(closed) {
fs->files[fd] = NULL;
}
nn_unlock(&fs->ctx, fs->lock);
nn_return(computer, nn_values_boolean(closed));
}
@ -441,18 +402,15 @@ void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_compute
return;
}
nn_lock(&fs->ctx, fs->lock);
nn_size_t spaceRemaining = nn_fs_getSpaceRemaining(fs);
size_t spaceRemaining = nn_fs_getSpaceRemaining(fs);
// overwriting would still work but OC does the same thing so...
if(spaceRemaining < len) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "out of space");
return;
}
void *file = nn_fs_unwrapFD(fs, fd);
if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "bad file descriptor");
return;
}
@ -460,7 +418,6 @@ void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_compute
nn_bool_t written = fs->table.write(fs->table.userdata, file, buf, len);
nn_return(computer, nn_values_boolean(written));
if(written) nn_fs_invalidateSpaceUsed(fs);
nn_unlock(&fs->ctx, fs->lock);
nn_fs_writeCost(fs, len, component);
}
@ -476,10 +433,8 @@ void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer
if(len > capacity) len = capacity;
nn_size_t byteLen = len;
nn_lock(&fs->ctx, fs->lock);
void *file = nn_fs_unwrapFD(fs, fd);
if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "bad file descriptor");
return;
}
@ -487,13 +442,11 @@ void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
char *buf = nn_alloc(alloc, byteLen);
if(buf == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "out of memory");
return;
}
nn_size_t readLen = fs->table.read(fs->table.userdata, file, buf, byteLen);
nn_unlock(&fs->ctx, fs->lock);
if(readLen > 0) {
// Nothing read means EoF.
nn_return_string(computer, buf, readLen);
@ -527,16 +480,13 @@ void nn_fs_seek(nn_filesystem *fs, void *_, nn_component *component, nn_computer
return;
}
nn_lock(&fs->ctx, fs->lock);
void *file = nn_fs_unwrapFD(fs, fd);
if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "bad file descriptor");
return;
}
nn_size_t pos = fs->table.seek(fs->table.userdata, file, whence, off);
nn_unlock(&fs->ctx, fs->lock);
nn_return_integer(computer, pos);
}

View File

@ -131,23 +131,22 @@ void nni_gpu_set(nni_gpu *gpu, void *_, nn_component *component, nn_computer *co
return;
}
if(!nn_unicode_validate(s)) {
nn_setCError(computer, "invalid utf-8");
return;
}
int current = 0;
int len = 0;
while(s[current] != 0) {
if(nn_unicode_isValidCodepoint(s + current)) {
int codepoint = nn_unicode_codepointAt(s, current);
nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current));
current += nn_unicode_codepointSize(codepoint);
} else {
unsigned int codepoint = (unsigned char)s[current];
nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current));
current++;
}
int codepoint = nn_unicode_codepointAt(s, current);
nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current));
if(isVertical) {
y++;
} else {
x++;
}
current += nn_unicode_codepointSize(codepoint);
len++;
}

View File

@ -1,74 +0,0 @@
#include "../neonucleus.h"
// TODO: make it allocate lazily
typedef struct nn_vdrive {
nn_Context ctx;
char *buffer;
nn_size_t sectorSize;
nn_size_t capacity;
char label[NN_LABEL_SIZE];
nn_size_t labelLen;
} nn_vdrive;
static void nni_vdrive_deinit(nn_vdrive *vdrive) {
nn_Alloc a = vdrive->ctx.allocator;
nn_dealloc(&a, vdrive->buffer, vdrive->capacity);
nn_dealloc(&a, vdrive, sizeof(nn_vdrive));
}
static void nni_vdrive_getLabel(nn_vdrive *vdrive, char *buf, nn_size_t *buflen) {
nn_memcpy(buf, vdrive->label, vdrive->labelLen);
*buflen = vdrive->labelLen;
}
static nn_size_t nni_vdrive_setLabel(nn_vdrive *vdrive, const char *buf, nn_size_t buflen) {
if(buflen > NN_LABEL_SIZE) buflen = NN_LABEL_SIZE;
nn_memcpy(vdrive->label, buf, buflen);
vdrive->labelLen = buflen;
return buflen;
}
static void nni_vdrive_readSector(nn_vdrive *vdrive, int sector, char *buf) {
nn_memcpy(buf, vdrive->buffer + (sector - 1) * vdrive->sectorSize, vdrive->sectorSize);
}
static void nni_vdrive_writeSector(nn_vdrive *vdrive, int sector, const char *buf) {
nn_memcpy(vdrive->buffer + (sector - 1) * vdrive->sectorSize, buf, vdrive->sectorSize);
}
nn_drive *nn_volatileDrive(nn_Context *context, nn_vdriveOptions opts, nn_driveControl control) {
nn_Alloc *alloc = &context->allocator;
char *buffer = nn_alloc(alloc, opts.capacity);
if(buffer == NULL) return NULL;
nn_vdrive *drive = nn_alloc(alloc, sizeof(nn_vdrive));
if(drive == NULL) {
nn_dealloc(alloc, buffer, opts.capacity);
return NULL;
}
drive->ctx = *context;
drive->buffer = buffer;
drive->sectorSize = opts.sectorSize;
drive->capacity = opts.capacity;
nn_memcpy(drive->label, opts.label, opts.labelLen);
drive->labelLen = opts.labelLen;
if(opts.data == NULL) {
nn_memset(buffer, 0, opts.capacity);
} else {
nn_memcpy(buffer, opts.data, opts.capacity);
}
nn_driveTable table = {
.userdata = drive,
.deinit = (void *)nni_vdrive_deinit,
.getLabel = (void *)nni_vdrive_getLabel,
.setLabel = (void *)nni_vdrive_setLabel,
.readSector = (void *)nni_vdrive_readSector,
.writeSector = (void *)nni_vdrive_writeSector,
.sectorSize = opts.sectorSize,
.platterCount = opts.platterCount,
.capacity = opts.capacity,
};
return nn_newDrive(context, table, control);
}

View File

@ -1,98 +0,0 @@
#include "../neonucleus.h"
typedef struct nn_veeprom {
nn_Context ctx;
char *code;
nn_size_t codeLen;
nn_size_t codeSize;
char *data;
nn_size_t dataLen;
nn_size_t dataSize;
char label[NN_LABEL_SIZE];
nn_size_t labelLen;
nn_bool_t isReadOnly;
} nn_veeprom;
static void nni_veeprom_deinit(nn_veeprom *veeprom) {
nn_Alloc a = veeprom->ctx.allocator;
nn_dealloc(&a, veeprom->code, veeprom->codeSize);
nn_dealloc(&a, veeprom->data, veeprom->dataSize);
nn_dealloc(&a, veeprom, sizeof(nn_veeprom));
}
static void nni_veeprom_getLabel(nn_veeprom *veeprom, char *buf, nn_size_t *buflen) {
nn_memcpy(buf, veeprom->label, veeprom->labelLen);
*buflen = veeprom->labelLen;
}
static nn_size_t nni_veeprom_setLabel(nn_veeprom *veeprom, const char *buf, nn_size_t buflen) {
if(buflen > NN_LABEL_SIZE) buflen = NN_LABEL_SIZE;
nn_memcpy(veeprom->label, buf, buflen);
veeprom->labelLen = buflen;
return buflen;
}
static nn_size_t nni_veeprom_get(nn_veeprom *veeprom, char *buf) {
nn_memcpy(buf, veeprom->code, veeprom->codeLen);
return veeprom->codeLen;
}
static void nni_veeprom_set(nn_veeprom *veeprom, const char *buf, nn_size_t len) {
nn_memcpy(veeprom->code, buf, len);
veeprom->codeLen = len;
}
static nn_size_t nni_veeprom_getData(nn_veeprom *veeprom, char *buf) {
nn_memcpy(buf, veeprom->data, veeprom->dataLen);
return veeprom->dataLen;
}
static void nni_veeprom_setData(nn_veeprom *veeprom, const char *buf, nn_size_t len) {
nn_memcpy(veeprom->data, buf, len);
veeprom->dataLen = len;
}
static nn_bool_t nni_veeprom_isReadonly(nn_veeprom *eeprom) {
return eeprom->isReadOnly;
}
static void nni_veeprom_makeReadonly(nn_veeprom *eeprom) {
eeprom->isReadOnly = true;
}
nn_eeprom *nn_volatileEEPROM(nn_Context *context, nn_veepromOptions opts, nn_eepromControl control) {
nn_Alloc *a = &context->allocator;
// TODO: handle OOM
nn_veeprom *veeprom = nn_alloc(a, sizeof(nn_veeprom));
veeprom->ctx = *context;
veeprom->codeSize = opts.size;
veeprom->code = nn_alloc(a, veeprom->codeSize);
veeprom->codeLen = opts.len;
veeprom->dataSize = opts.dataSize;
veeprom->data = nn_alloc(a, veeprom->dataSize);
veeprom->dataLen = opts.dataLen;
veeprom->isReadOnly = opts.isReadOnly;
veeprom->labelLen = opts.labelLen;
nn_memcpy(veeprom->label, opts.label, veeprom->labelLen);
nn_memcpy(veeprom->code, opts.code, veeprom->codeLen);
nn_memcpy(veeprom->data, opts.data, veeprom->dataLen);
nn_eepromTable table = {
.userdata = veeprom,
.deinit = (void *)nni_veeprom_deinit,
.size = opts.size,
.dataSize = opts.dataSize,
.getLabel = (void *)nni_veeprom_getLabel,
.setLabel = (void *)nni_veeprom_setLabel,
.get = (void *)nni_veeprom_get,
.set = (void *)nni_veeprom_set,
.getData = (void *)nni_veeprom_getData,
.setData = (void *)nni_veeprom_setData,
.isReadonly = (void *)nni_veeprom_isReadonly,
.makeReadonly = (void *)nni_veeprom_makeReadonly,
};
return nn_newEEPROM(context, table, control);
}

View File

@ -367,11 +367,7 @@ nn_component *nn_newComponent(nn_computer *computer, nn_address address, int slo
computer->componentLen++;
}
if(address == NULL) {
c->address = nn_randomUUID(&computer->universe->ctx);
} else {
c->address = nn_strdup(&computer->universe->ctx.allocator, address);
}
c->address = nn_strdup(&computer->universe->ctx.allocator, address);
if(c->address == NULL) return NULL;
c->table = table;
c->slot = slot;

View File

@ -1,4 +1,5 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@ -290,6 +291,47 @@ bool ne_fs_exists(nn_address addr, const char *path) {
return FileExists(p) || DirectoryExists(p);
}
typedef struct ne_drive {
FILE *file;
} ne_drive;
void ne_drive_close(nn_component *component, ne_drive *drive) {
fclose(drive->file);
}
nn_driveControl ne_drive_getControl(nn_component *component, ne_drive *_) {
return (nn_driveControl){};
}
size_t ne_drive_getPlatterCount(nn_component *component, ne_drive *_) {
return 1;
}
size_t ne_drive_getSectorSize(nn_component *component, ne_drive *_) {
return 512;
}
size_t ne_drive_getCapacity(nn_component *component, ne_drive *drive) {
fseek(drive->file, 0, SEEK_END);
return ftell(drive->file);
}
void ne_drive_readSector(nn_component *component, ne_drive *drive, int shifted_sector, char *buf) {
int sector = shifted_sector - 1;
size_t sectorSize = ne_drive_getSectorSize(component, drive);
size_t offset = sector * sectorSize;
fseek(drive->file, offset, SEEK_SET);
fread(buf, sizeof(char), sectorSize, drive->file);
}
void ne_drive_writeSector(nn_component *component, ne_drive *drive, int shifted_sector, const char *buf) {
int sector = shifted_sector - 1;
size_t sectorSize = ne_drive_getSectorSize(component, drive);
size_t offset = sector * sectorSize;
fseek(drive->file, offset, SEEK_SET);
fwrite(buf, sizeof(char), sectorSize, drive->file);
// this is probably not needed but i believe someone isn't running the deinit
fflush(drive->file);
}
int keycode_to_oc(int keycode) {
switch (keycode) {
case KEY_NULL:
@ -614,7 +656,7 @@ int main() {
nn_eeprom *genericEEPROM = nn_newEEPROM(&ctx, genericEEPROMTable, ne_eeprom_ctrl);
nn_addEEPROM(computer, NULL, 0, genericEEPROM);
nn_addEeprom(computer, "luaBios.lua", 0, genericEEPROM);
nn_address fsFolder = "OpenOS";
nn_filesystemTable genericFSTable = {
@ -640,28 +682,28 @@ int main() {
.seek = (void *)ne_fs_seek,
};
nn_filesystem *genericFS = nn_newFilesystem(&ctx, genericFSTable, ne_fs_ctrl);
nn_addFileSystem(computer, NULL, 1, genericFS);
nn_addFileSystem(computer, fsFolder, 1, genericFS);
nn_vdriveOptions vdriveOpts = {
.sectorSize = 512,
.capacity = 1*1024*1024,
.platterCount = 1,
.labelLen = 0,
.data = NULL,
ne_drive drive = {
.file = fopen("data/drive.img", "r+")
};
nn_driveControl vdriveCtrl = {
.readSectorsPerTick = 32768,
.writeSectorsPerTick = 16384,
.seekSectorsPerTick = 8192,
.readHeatPerSector = 0.0015,
.writeHeatPerSector = 0.015,
.motorHeatPerSector = 0.000005,
.readEnergyPerSector = 0.0015,
.writeEnergyPerSector = 0.015,
.motorEnergyPerSector = 0.00005,
assert(drive.file != NULL);
nn_drive genericDrive = {
.refc = 0,
.userdata = &drive,
.deinit = (void *)ne_drive_close,
.control = (void *)ne_drive_getControl,
.getLabel = ne_fs_getLabel,
.setLabel = ne_fs_setLabel,
.getPlatterCount = (void *)ne_drive_getPlatterCount,
.getSectorSize = (void *)ne_drive_getSectorSize,
.getCapacity = (void *)ne_drive_getCapacity,
.readSector = (void *)ne_drive_readSector,
.writeSector = (void *)ne_drive_writeSector,
};
nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl);
nn_addDrive(computer, NULL, 4, genericDrive);
nn_addDrive(computer, "drive.img", 4, &genericDrive);
int maxWidth = 80, maxHeight = 32;
@ -669,7 +711,7 @@ int main() {
nn_setDepth(s, 4); // looks cool
nn_addKeyboard(s, "shitty keyboard");
nn_mountKeyboard(computer, "shitty keyboard", 2);
nn_addScreen(computer, NULL, 2, s);
nn_addScreen(computer, "Main Screen", 2, s);
ne_premappedPixel *premap = ne_allocPremap(maxWidth, maxHeight);
@ -689,7 +731,7 @@ int main() {
.energyPerVRAMChange = 0.0015,
};
nn_addGPU(computer, NULL, 3, &gpuCtrl);
nn_addGPU(computer, "RTX 6090", 3, &gpuCtrl);
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(800, 600, "emulator");

View File

@ -196,7 +196,6 @@ double nn_randf(nn_Rng *rng);
// returns from 0 to 1 (exclusive)
double nn_randfe(nn_Rng *rng);
typedef struct nn_Context {
nn_Alloc allocator;
nn_LockManager lockManager;
@ -282,7 +281,6 @@ void nn_dealloc(nn_Alloc *alloc, void *memory, nn_size_t size);
char *nn_strdup(nn_Alloc *alloc, const char *s);
void *nn_memdup(nn_Alloc *alloc, const void *buf, nn_size_t len);
void nn_deallocStr(nn_Alloc *alloc, char *s);
nn_address nn_randomUUID(nn_Context *ctx);
nn_guard *nn_newGuard(nn_Context *context);
void nn_lock(nn_Context *context, nn_guard *guard);
@ -300,8 +298,6 @@ nn_bool_t nn_decRef(nn_refc *refc);
// Unicode (more specifically, UTF-8) stuff
nn_bool_t nn_unicode_validate(const char *s);
// expects NULL terminator
nn_bool_t nn_unicode_isValidCodepoint(const char *s);
// returned string must be nn_deallocStr()'d
char *nn_unicode_char(nn_Alloc *alloc, unsigned int *codepoints, nn_size_t codepointCount);
// returned array must be nn_dealloc()'d
@ -605,24 +601,11 @@ typedef struct nn_eepromTable {
typedef struct nn_eeprom nn_eeprom;
typedef struct nn_veepromOptions {
const char *code;
nn_size_t len;
nn_size_t size;
const char *data;
nn_size_t dataLen;
nn_size_t dataSize;
char label[NN_LABEL_SIZE];
nn_size_t labelLen;
nn_bool_t isReadOnly;
} nn_veepromOptions;
nn_eeprom *nn_newEEPROM(nn_Context *context, nn_eepromTable table, nn_eepromControl control);
nn_eeprom *nn_volatileEEPROM(nn_Context *context, nn_veepromOptions opts, nn_eepromControl control);
nn_guard *nn_getEEPROMLock(nn_eeprom *eeprom);
void nn_retainEEPROM(nn_eeprom *eeprom);
nn_bool_t nn_destroyEEPROM(nn_eeprom *eeprom);
nn_component *nn_addEEPROM(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom);
nn_component *nn_addEeprom(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom);
// FileSystem
typedef struct nn_filesystemControl {
@ -708,42 +691,28 @@ typedef struct nn_driveControl {
nn_bool_t reversable;
} nn_driveControl;
typedef struct nn_driveTable {
typedef struct nn_drive {
nn_refc refc;
void *userdata;
void (*deinit)(void *userdata);
void (*deinit)(nn_component *component, void *userdata);
void (*getLabel)(void *userdata, char *buf, nn_size_t *buflen);
nn_size_t (*setLabel)(void *userdata, const char *buf, nn_size_t buflen);
nn_driveControl (*control)(nn_component *component, void *userdata);
void (*getLabel)(nn_component *component, void *userdata, char *buf, nn_size_t *buflen);
nn_size_t (*setLabel)(nn_component *component, void *userdata, const char *buf, nn_size_t buflen);
nn_size_t platterCount;
nn_size_t capacity;
nn_size_t sectorSize;
nn_size_t (*getPlatterCount)(nn_component *component, void *userdata);
nn_size_t (*getCapacity)(nn_component *component, void *userdata);
nn_size_t (*getSectorSize)(nn_component *component, void *userdata);
// sectors start at 1 as per OC.
void (*readSector)(void *userdata, int sector, char *buf);
void (*writeSector)(void *userdata, int sector, const char *buf);
void (*readSector)(nn_component *component, void *userdata, int sector, char *buf);
void (*writeSector)(nn_component *component, void *userdata, int sector, const char *buf);
// readByte and writeByte will internally use readSector and writeSector. This is to ensure they are handled *consistently.*
// Also makes the interface less redundant
} nn_driveTable;
typedef struct nn_vdriveOptions {
nn_size_t sectorSize;
nn_size_t platterCount;
nn_size_t capacity;
const char *data;
char label[NN_LABEL_SIZE];
nn_size_t labelLen;
} nn_vdriveOptions;
typedef struct nn_drive nn_drive;
nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control);
nn_drive *nn_volatileDrive(nn_Context *context, nn_vdriveOptions opts, nn_driveControl control);
nn_guard *nn_getDriveLock(nn_drive *drive);
void nn_retainDrive(nn_drive *drive);
nn_bool_t nn_destroyDrive(nn_drive *drive);
} nn_drive;
nn_drive *nn_volatileDrive(nn_size_t capacity, nn_size_t platterCount, nn_driveControl *control);
nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive);
// Screens and GPUs

View File

@ -17,14 +17,6 @@ local function copy(v, p)
end
end
local function spcall(f, ...)
local t = {pcall(f, ...)}
if t[1] then
return table.unpack(t, 2)
end
return nil, t[2]
end
local function nextDeadline()
return computer.uptime() + 5
end
@ -400,9 +392,40 @@ sandbox = {
utf8 = copy(utf8),
unicode = copy(unicode, {
wtrunc = function (str,space)
space = space - 1
return str:sub(1,(space >= utf8.len(str)) and (#str) or (utf8.offset(str,space+1)-1))
end,
isWide = function(s) return unicode.wlen(s) > unicode.len(s) end,
upper = string.upper,
lower = string.lower,
--[[
sub = function (str,a,b)
if not b then b = utf8.len(str) end
if not a then a = 1 end
-- a = math.max(a,1)
if a < 0 then
-- negative
a = utf8.len(str) + a + 1
end
if b < 0 then
b = utf8.len(str) + b + 1
end
if a > b then return "" end
if b >= utf8.len(str) then b = #str else b = utf8.offset(str,b+1)-1 end
if a > utf8.len(str) then return "" end
a = utf8.offset(str,a)
return str:sub(a,b)
-- return str:sub(a, b)
end,
]]
}),
checkArg = checkArg,
component = libcomponent,

View File

@ -59,12 +59,12 @@ const char *testLuaArch_pushlstring(lua_State *L, const char *s, size_t len) {
}
return lua_pushlstring(L, s, len);
}
const char *testLuaArch_pushstring(lua_State *L, const char *s) {
size_t len = strlen(s);
return testLuaArch_pushlstring(L, s, len);
}
void *testLuaArch_alloc(testLuaArch *arch, void *ptr, size_t osize, size_t nsize) {
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(arch->computer));
if(nsize == 0) {

View File

@ -162,36 +162,6 @@ static nn_bool_t nn_unicode_is_continuation(unsigned char byte) {
return (byte >> 6) == 0b10;
}
nn_bool_t nn_unicode_isValidCodepoint(const char *s) {
if(s[0] <= 0x7F) {
return true;
} else if((s[0] >> 5) == 0b110) {
if (!nn_unicode_is_continuation(s[1])) {
return false;
}
} else if((s[0] >> 4) == 0b1110) {
if (!nn_unicode_is_continuation(s[1])) {
return false;
}
if (!nn_unicode_is_continuation(s[2])) {
return false;
}
} else if((s[0] >> 3) == 0b11110) {
if (!nn_unicode_is_continuation(s[1])) {
return false;
}
if (!nn_unicode_is_continuation(s[2])) {
return false;
}
if (!nn_unicode_is_continuation(s[3])) {
return false;
}
} else {
return false;
}
return true;
}
nn_bool_t nn_unicode_validate(const char *b) {
const unsigned char* s = (const unsigned char*)b;
while (*s) {

View File

@ -104,36 +104,6 @@ void nn_deallocStr(nn_Alloc *alloc, char *s) {
nn_dealloc(alloc, s, nn_strlen(s)+1);
}
static void nni_randomHex(nn_Context *ctx, char *buf, nn_size_t len) {
const char *hex = "0123456789abcdef";
for(nn_size_t i = 0; i < len; i++) {
int r = nn_rand(&ctx->rng) % 16;
buf[i] = hex[r];
}
}
nn_address nn_randomUUID(nn_Context *ctx) {
nn_address addr = nn_alloc(&ctx->allocator, 37);
if(addr == NULL) return NULL;
nni_randomHex(ctx, addr + 0, 8);
addr[8] = '-';
nni_randomHex(ctx, addr + 9, 4);
addr[13] = '-';
nni_randomHex(ctx, addr + 14, 4);
addr[18] = '-';
nni_randomHex(ctx, addr + 19, 4);
addr[23] = '-';
nni_randomHex(ctx, addr + 24, 12);
addr[36] = '\0';
// UUIDv4 variant 1
addr[14] = '4';
addr[19] = '1';
return addr;
}
nn_size_t nn_rand(nn_Rng *rng) {
return rng->proc(rng->userdata);
}