Merge pull request #237 from ThakeeNathees/term

new Fiber objects falsely garbage collected -- fixed
This commit is contained in:
Thakee Nathees 2022-05-26 08:22:58 +05:30 committed by GitHub
commit e458682486
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 204 additions and 101 deletions

View File

@ -62,12 +62,13 @@ def log(*msg):
sys.stderr.write(message + '\n')
def parse(path):
dir = dirname(path).replace('\\', '/') ## Windows.
text = ""
with open(path, 'r') as fp:
for line in fp.readlines():
if "//<< AMALG_INLINE >>" in line:
path = join(dirname(path), _get_include_path(line))
path = path.replace('\\', '/') ## Aaah windows path.
path = join(dir, _get_include_path(line))
path = path.replace('\\', '/')
text += parse(path) + '\n'
else: text += line

View File

@ -34,8 +34,7 @@ ALLOW_LONG_LINES = ('http://', 'https://', '<script ', '<link ', '<svg ')
IGNORE_FILES = (
"cli/modules/pknative.gen.c", ## FIXME: set gen path.
"cli/argparse.h", ## FIXME: collect all thirdparty files.
"src/libs/tp_dirent.h",
"src/libs/tp_cwalk.h",
"src/libs/ext_term.c",
)
## A list of directory, contains C source files to perform static checks.

View File

@ -2734,9 +2734,12 @@ static void compileFunction(Compiler* compiler, FuncType fn_type) {
if (compiler->parser.has_syntax_error) return;
// The function will register itself in the owner's constant pool and it's
// GC root so we don't need to push it to temp references.
int fn_index;
Function* func = newFunction(compiler->parser.vm, name, name_length,
compiler->module, false, NULL, &fn_index);
func->is_method = (fn_type == FUNC_METHOD || fn_type == FUNC_CONSTRUCTOR);
checkMaxConstantsReached(compiler, fn_index);

View File

@ -81,6 +81,7 @@ static char* stdinRead(PKVM* vm);
static char* loadScript(PKVM* vm, const char* path);
void* pkRealloc(PKVM* vm, void* ptr, size_t size) {
ASSERT(vm->config.realloc_fn != NULL, "PKVM's allocator was NULL.");
#if TRACE_MEMORY
void* newptr = vm->config.realloc_fn(ptr, size, vm->config.user_data);
@ -123,6 +124,7 @@ PKVM* pkNewVM(PkConfiguration* config) {
vm->working_set = (Object**)vm->config.realloc_fn(
NULL, sizeof(Object*) * vm->working_set_capacity, NULL);
vm->next_gc = INITIAL_GC_SIZE;
vm->collecting_garbage = false;
vm->min_heap_size = MIN_HEAP_SIZE;
vm->heap_fill_percent = HEAP_FILL_PERCENT;
@ -178,7 +180,12 @@ void pkSetUserData(PKVM* vm, void* user_data) {
PkHandle* pkNewModule(PKVM* vm, const char* name) {
CHECK_ARG_NULL(name);
Module* module = newModuleInternal(vm, name);
return vmNewHandle(vm, VAR_OBJ(module));
vmPushTempRef(vm, &module->_super); // module.
PkHandle* handle = vmNewHandle(vm, VAR_OBJ(module));
vmPopTempRef(vm); // module.
return handle;
}
void pkRegisterModule(PKVM* vm, PkHandle* module) {
@ -218,7 +225,10 @@ PkHandle* pkNewClass(PKVM* vm, const char* name,
class_->new_fn = new_fn;
class_->delete_fn = delete_fn;
return vmNewHandle(vm, VAR_OBJ(class_));
vmPushTempRef(vm, &class_->_super); // class_.
PkHandle* handle = vmNewHandle(vm, VAR_OBJ(class_));
vmPopTempRef(vm); // class_.
return handle;
}
void pkClassAddMethod(PKVM* vm, PkHandle* cls,
@ -236,6 +246,8 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
Function* fn = newFunction(vm, name, (int)strlen(name),
class_->owner, true, NULL, NULL);
vmPushTempRef(vm, &fn->_super); // fn.
fn->arity = arity;
fn->is_method = true;
fn->native = fptr;
@ -245,7 +257,9 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
// won't be garbage collected (class handle has reference to the module).
Closure* method = newClosure(vm, fn);
vmPopTempRef(vm); // fn.
vmPushTempRef(vm, &method->_super); // method.
{
if (strcmp(name, CTOR_NAME) == 0) {
class_->ctor = method;
@ -254,6 +268,8 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
pkClosureBufferWrite(&class_->methods, vm, method);
vmPopTempRef(vm); // method.
}
}
vmPopTempRef(vm); // method.
}
void pkReleaseHandle(PKVM* vm, PkHandle* handle) {
@ -765,7 +781,11 @@ bool pkSetAttribute(PKVM* vm, int instance, const char* name, int value) {
VALIDATE_SLOT_INDEX(instance);
VALIDATE_SLOT_INDEX(value);
varSetAttrib(vm, SLOT(instance), newString(vm, name), SLOT(value));
String* sname = newString(vm, name);
vmPushTempRef(vm, &sname->_super); // sname.
varSetAttrib(vm, SLOT(instance), sname, SLOT(value));
vmPopTempRef(vm); // sname.
return !VM_HAS_ERROR(vm);
}
@ -776,12 +796,19 @@ bool pkGetAttribute(PKVM* vm, int instance, const char* name,
VALIDATE_SLOT_INDEX(instance);
VALIDATE_SLOT_INDEX(index);
SET_SLOT(index, varGetAttrib(vm, SLOT(instance), newString(vm, name)));
String* sname = newString(vm, name);
vmPushTempRef(vm, &sname->_super); // sname.
SET_SLOT(index, varGetAttrib(vm, SLOT(instance), sname));
vmPopTempRef(vm); // sname.
return !VM_HAS_ERROR(vm);
}
static Var _newInstance(PKVM* vm, Class* cls, int argc, Var* argv) {
Var instance = preConstructSelf(vm, cls);
if (VM_HAS_ERROR(vm)) return VAR_NULL;
if (IS_OBJ(instance)) vmPushTempRef(vm, AS_OBJ(instance)); // instance.
Closure* ctor = cls->ctor;
while (ctor == NULL) {
@ -791,6 +818,7 @@ static Var _newInstance(PKVM* vm, Class* cls, int argc, Var* argv) {
}
if (ctor != NULL) vmCallMethod(vm, instance, ctor, argc, argv, NULL);
if (IS_OBJ(instance)) vmPopTempRef(vm); // instance.
return instance;
}
@ -860,8 +888,12 @@ bool pkCallMethod(PKVM* vm, int instance, const char* method,
if (ret >= 0) VALIDATE_SLOT_INDEX(ret);
bool is_method = false;
Var callable = getMethod(vm, SLOT(instance), newString(vm, method),
String* smethod = newString(vm, method);
vmPushTempRef(vm, &smethod->_super); // smethod.
Var callable = getMethod(vm, SLOT(instance), smethod,
&is_method);
vmPopTempRef(vm); // smethod.
if (VM_HAS_ERROR(vm)) return false;
// Calls a class == construct.

View File

@ -97,7 +97,7 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
switch (obj->type) {
case OBJ_STRING: {
vm->bytes_allocated += sizeof(String);
vm->bytes_allocated += ((size_t)((String*)obj)->length + 1);
vm->bytes_allocated += ((size_t)((String*)obj)->capacity);
} break;
case OBJ_LIST: {
@ -149,11 +149,13 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) {
markObject(vm, &func->owner->_super);
if (!func->is_native) {
// If a garbage collection is triggered when allocating a name string
// for this function, it's [fn] property will be NULL.
if (!func->is_native && func->fn != NULL) {
Fn* fn = func->fn;
vm->bytes_allocated += sizeof(Fn);
vm->bytes_allocated += sizeof(uint8_t)* fn->opcodes.capacity;
vm->bytes_allocated += sizeof(uint8_t) * fn->opcodes.capacity;
vm->bytes_allocated += sizeof(uint32_t) * fn->oplines.capacity;
}
} break;
@ -293,14 +295,14 @@ String* newStringVaArgs(PKVM* vm, const char* fmt, va_list args) {
List* newList(PKVM* vm, uint32_t size) {
List* list = ALLOCATE(vm, List);
vmPushTempRef(vm, &list->_super);
vmPushTempRef(vm, &list->_super); // list.
varInitObject(&list->_super, vm, OBJ_LIST);
pkVarBufferInit(&list->elements);
if (size > 0) {
pkVarBufferFill(&list->elements, vm, VAR_NULL, size);
list->elements.count = 0;
}
vmPopTempRef(vm);
vmPopTempRef(vm); // list.
return list;
}
@ -323,13 +325,9 @@ Range* newRange(PKVM* vm, double from, double to) {
Module* newModule(PKVM* vm) {
Module* module = ALLOCATE(vm, Module);
memset(module, 0, sizeof(Module));
varInitObject(&module->_super, vm, OBJ_MODULE);
module->path = NULL;
module->name = NULL;
module->initialized = false;
module->body = NULL;
pkVarBufferInit(&module->globals);
pkUintBufferInit(&module->global_names);
pkVarBufferInit(&module->constants);
@ -343,6 +341,7 @@ Function* newFunction(PKVM* vm, const char* name, int length,
int* fn_index) {
Function* func = ALLOCATE(vm, Function);
memset(func, 0, sizeof(Function));
varInitObject(&func->_super, vm, OBJ_FUNC);
vmPushTempRef(vm, &func->_super); // func
@ -388,10 +387,7 @@ Closure* newClosure(PKVM* vm, Function* fn) {
varInitObject(&closure->_super, vm, OBJ_CLOSURE);
closure->fn = fn;
for (int i = 0; i < fn->upvalue_count; i++) {
closure->upvalues[i] = NULL;
}
memset(closure->upvalues, 0, sizeof(Upvalue*) * fn->upvalue_count);
return closure;
}
@ -411,11 +407,15 @@ Fiber* newFiber(PKVM* vm, Closure* closure) {
Fiber* fiber = ALLOCATE(vm, Fiber);
// Not sure why this memset is needed here. If it doesn't then remove it.
// If a garbage collection is triggered here, and the fiber isn't fully
// constructed -> it's fields are not intialized yet, would cause a crash
// so we need to memset here.
memset(fiber, 0, sizeof(Fiber));
varInitObject(&fiber->_super, vm, OBJ_FIBER);
vmPushTempRef(vm, &fiber->_super); // fiber.
fiber->state = FIBER_NEW;
fiber->closure = closure;
@ -431,6 +431,7 @@ Fiber* newFiber(PKVM* vm, Closure* closure) {
if (stack_size == 0) stack_size++;
fiber->stack = ALLOCATE_ARRAY(vm, Var, stack_size);
ASSERT(fiber->stack != NULL, "Out of memory");
fiber->stack_size = stack_size;
fiber->ret = fiber->stack;
fiber->sp = fiber->stack + 1;
@ -462,6 +463,8 @@ Fiber* newFiber(PKVM* vm, Closure* closure) {
// but if we're trying to debut it may crash when dumping the return value).
*fiber->ret = VAR_NULL;
vmPopTempRef(vm); // fiber.
return fiber;
}
@ -470,6 +473,12 @@ Class* newClass(PKVM* vm, const char* name, int length,
const char* docstring, int* cls_index) {
Class* cls = ALLOCATE(vm, Class);
// If the garbage collection trigged bellow while allocating for
// [cls->name] or other properties, the calss is in the root (temp ref)
// and it's property [cls->name] is un initialized, which cause a crash.
memset(cls, 0, sizeof(Class));
varInitObject(&cls->_super, vm, OBJ_CLASS);
vmPushTempRef(vm, &cls->_super); // class.
@ -477,12 +486,7 @@ Class* newClass(PKVM* vm, const char* name, int length,
pkClosureBufferInit(&cls->methods);
cls->class_of = PK_INSTANCE;
cls->owner = NULL;
cls->super_class = super;
cls->docstring = NULL;
cls->ctor = NULL;
cls->new_fn = NULL;
cls->delete_fn = NULL;
// Builtin types doesn't belongs to a module.
if (module != NULL) {
@ -504,36 +508,38 @@ Instance* newInstance(PKVM* vm, Class* cls) {
"class with newInstance() function.");
Instance* inst = ALLOCATE(vm, Instance);
memset(inst, 0, sizeof(Instance));
varInitObject(&inst->_super, vm, OBJ_INST);
vmPushTempRef(vm, &inst->_super); // inst.
inst->cls = cls;
inst->attribs = newMap(vm);
if (cls->new_fn != NULL) {
inst->native = cls->new_fn(vm);
} else {
inst->native = NULL;
}
inst->attribs = newMap(vm);
vmPopTempRef(vm); // inst.
return inst;
}
List* rangeAsList(PKVM* vm, Range* self) {
List* list;
if (self->from < self->to) {
list = newList(vm, (uint32_t)(self->to - self->from));
List* list = newList(vm, (uint32_t)(self->to - self->from));
vmPushTempRef(vm, &list->_super); // list.
for (double i = self->from; i < self->to; i++) {
pkVarBufferWrite(&list->elements, vm, VAR_NUM(i));
}
return list;
vmPopTempRef(vm); // list.
} else {
list = newList(vm, 0);
return list;
}
return list;
return newList(vm, 0);
}
String* stringLower(PKVM* vm, String* self) {

View File

@ -27,10 +27,24 @@ void* vmRealloc(PKVM* vm, void* memory, size_t old_size, size_t new_size) {
// Track the total allocated memory of the VM to trigger the GC.
// if vmRealloc is called for freeing, the old_size would be 0 since
// deallocated bytes are traced by garbage collector.
//
// If we're running a garbage collection, VM's byte allocated will be
// re-calculated at vmCollectGarbage() which is equal to the remaining
// objects after clening the garbage. And clearing a garbage will
// recursively invoke this function so we shouldn't modify it.
if (!vm->collecting_garbage) {
vm->bytes_allocated += new_size - old_size;
}
// If we're garbage collecting no new allocation is allowed.
ASSERT(!vm->collecting_garbage || new_size == 0,
"No new allocation is allowed while garbage collection is running.");
if (new_size > 0 && vm->bytes_allocated > vm->next_gc) {
ASSERT(vm->collecting_garbage == false, OOPS);
vm->collecting_garbage = true;
vmCollectGarbage(vm);
vm->collecting_garbage = false;
}
#if TRACE_MEMORY
@ -99,10 +113,6 @@ Module* vmGetModule(PKVM* vm, String* key) {
void vmCollectGarbage(PKVM* vm) {
// Reset VM's bytes_allocated value and count it again so that we don't
// required to know the size of each object that'll be freeing.
vm->bytes_allocated = 0;
// Mark builtin functions.
for (int i = 0; i < vm->builtins_count; i++) {
markObject(vm, &vm->builtins_funcs[i]->_super);
@ -139,11 +149,23 @@ void vmCollectGarbage(PKVM* vm) {
markObject(vm, &vm->fiber->_super);
}
// Reset VM's bytes_allocated value and count it again so that we don't
// required to know the size of each object that'll be freeing.
vm->bytes_allocated = 0;
// Pop the marked objects from the working set and push all of it's
// referenced objects. This will repeat till no more objects left in the
// working set.
popMarkedObjects(vm);
// Now [vm->bytes_allocated] is equal to the number of bytes allocated for
// the root objects which are marked above. Since we're garbage collecting
// freeObject() shouldn't modify vm->bytes_allocated. We ensure this by
// copying the value to [bytes_allocated] and check after freeing.
#ifdef DEBUG
size_t bytes_allocated = vm->bytes_allocated;
#endif
// Now sweep all the un-marked objects in then link list and remove them
// from the chain.
@ -166,6 +188,10 @@ void vmCollectGarbage(PKVM* vm) {
}
}
#ifdef DEBUG
ASSERT(bytes_allocated = vm->bytes_allocated, OOPS);
#endif
// Next GC heap size will be change depends on the byte we've left with now,
// and the [heap_fill_percent].
vm->next_gc = vm->bytes_allocated + (
@ -937,7 +963,9 @@ L_vm_main_loop:
ASSERT_INDEX(index, module->constants.count);
ASSERT(IS_OBJ_TYPE(module->constants.data[index], OBJ_FUNC), OOPS);
Function* fn = (Function*)AS_OBJ(module->constants.data[index]);
Closure* closure = newClosure(vm, fn);
vmPushTempRef(vm, &closure->_super); // closure.
// Capture the vaupes.
for (int i = 0; i < fn->upvalue_count; i++) {
@ -954,6 +982,8 @@ L_vm_main_loop:
}
PUSH(VAR_OBJ(closure));
vmPopTempRef(vm); // closure.
DISPATCH();
}

View File

@ -69,6 +69,10 @@ struct PKVM {
// The number of bytes that'll trigger the next GC.
size_t next_gc;
// True if PKVM is running a garbage collection, and no new allocation is
// allowed in this phase.
bool collecting_garbage;
// Minimum size the heap could get.
size_t min_heap_size;

View File

@ -8,6 +8,8 @@
#include "libs.h"
#endif
// Standard libraries.
void registerModuleMath(PKVM* vm);
void registerModuleTypes(PKVM* vm);
void registerModuleTime(PKVM* vm);
@ -15,6 +17,7 @@ void registerModuleIO(PKVM* vm);
void registerModulePath(PKVM* vm);
void registerModuleDummy(PKVM* vm);
// Registers the modules.
void registerLibs(PKVM* vm) {
registerModuleMath(vm);
registerModuleTypes(vm);
@ -24,6 +27,6 @@ void registerLibs(PKVM* vm) {
registerModuleDummy(vm);
}
// Cleanup the modules.
void cleanupLibs(PKVM* vm) {
}

View File

@ -144,6 +144,10 @@ DEF(_dummyCallMethod,
if (!pkCallMethod(vm, 1, method, 2, 3, 0)) return;
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleDummy(PKVM* vm) {
PkHandle* dummy = pkNewModule(vm, "dummy");

View File

@ -402,6 +402,10 @@ DEF(_fileTell, "") {
pkSetSlotNumber(vm, 0, (double) ftell(file->fp));
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleIO(PKVM* vm) {
PkHandle* io = pkNewModule(vm, "io");

View File

@ -181,6 +181,20 @@ DEF(stdMathRound,
pkSetSlotNumber(vm, 0, round(num));
}
DEF(stdMathRand,
"rand() -> num\n"
"Return a random runber in the range of 0..0x7fff.") {
// RAND_MAX is implementation dependent but is guaranteed to be at least
// 0x7fff on any standard library implementation.
// https://www.cplusplus.com/reference/cstdlib/RAND_MAX/
pkSetSlotNumber(vm, 0, rand() % 0x7fff);
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleMath(PKVM* vm) {
PkHandle* math = pkNewModule(vm, "math");
@ -208,6 +222,7 @@ void registerModuleMath(PKVM* vm) {
pkModuleAddFunction(vm, math, "atan", stdMathArcTangent, 1);
pkModuleAddFunction(vm, math, "log10", stdMathLog10, 1);
pkModuleAddFunction(vm, math, "round", stdMathRound, 1);
pkModuleAddFunction(vm, math, "rand", stdMathRand, 0);
pkRegisterModule(vm, math);
pkReleaseHandle(vm, math);

View File

@ -14,7 +14,7 @@
// Refactor the bellow macro includes.
#define _CWALK_IMPL
#include "tp_cwalk.h" //<< AMALG_INLINE >>
#include "thirdparty/cwalk/cwalk.h" //<< AMALG_INLINE >>
#undef _CWALK_IMPL
#include <errno.h>
@ -28,7 +28,7 @@
#include <direct.h>
#include <io.h>
#include "tp_dirent.h" //<< AMALG_INLINE >>
#include "thirdparty/dirent/dirent.h" //<< AMALG_INLINE >>
// access() function flag defines for windows.
// Reference :https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=msvc-170#remarks
@ -339,6 +339,10 @@ DEF(_pathIsDir, "") {
pkSetSlotBool(vm, 0, pathIsDir(path));
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModulePath(PKVM* vm) {
PkHandle* path = pkNewModule(vm, "path");

View File

@ -47,6 +47,10 @@ DEF(_timeSleep,
#endif
}
/*****************************************************************************/
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleTime(PKVM* vm) {
PkHandle* time = pkNewModule(vm, "time");

View File

@ -257,7 +257,7 @@ void _vectorRepr(PKVM* vm) {
}
/*****************************************************************************/
/* REGISTER TYPES */
/* MODULE REGISTER */
/*****************************************************************************/
void registerModuleTypes(PKVM* vm) {

21
src/libs/thirdparty/cwalk/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Leonard Iklé
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,27 +1,3 @@
/*
* MIT License
*
* Copyright (c) 2020 Leonard Iklé
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CWK_LIBRARY_H
#define CWK_LIBRARY_H

21
src/libs/thirdparty/dirent/LICENSE vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 1998-2019 Toni Ronkko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,27 +1,3 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 1998-2019 Toni Ronkko
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Dirent interface for Microsoft Visual Studio
*