diff -r c4b1341297e5 -r ba85a47ee414 src/Packages.cpp --- a/src/Packages.cpp Mon Jun 10 00:46:29 2013 +0100 +++ b/src/Packages.cpp Mon Jun 10 01:04:43 2013 +0100 @@ -1,226 +1,226 @@ -/* - * Copyright (C) 2012 David Anderson - * - * This file is part of SourcePawn. - * - * SourcePawn is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 3 of the License, or (at your option) - * any later version. - * - * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * SourcePawn. If not, see http://www.gnu.org/licenses/. - */ -#include -#include "Zone.h" -#include "Heap.h" -#include "Strings.h" -#include "Modules.h" -#include "Packages.h" -#include "FileSystem.h" -#include "List.h" -#include "Heap-inl.h" -#include "Handles-inl.h" - -using namespace ke; - -Package * -Package::NewNormalized(Zone *zone, Handle parent, Handle path, Handle name, unsigned flags) -{ - Local package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old))); - if (!package) - return NULL; - - // :TODO: assert path, name are atoms. - - package->flags_ = flags; - package->name_ = name; - package->parent_ = parent; - package->path_ = path; - package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL; - - return package; -} - -Package * -Package::New(Zone *zone, Handle parent, const char *path, Handle name, unsigned flags) -{ - Local strpath(zone, zone->makeSymbol(path)); - if (!strpath) - return NULL; - - return Package::NewNormalized(zone, parent, strpath, name, flags); -} - -bool -Package::add(Zone *zone, Handle obj) -{ - Local pkg(zone, this); - - assert(obj->parent() == pkg); - - if (!pkg->contents_) { - pkg->contents_ = List::New(zone); - if (!pkg->contents_) - return false; - } - -#ifndef NDEBUG - // Assert no duplicate names. - for (unsigned i = 0; i < pkg->contents_->length(); i++) - assert(pkg->contents_->at(i)->name() != obj->name()); -#endif - - if (!pkg->contents_->append(zone, obj)) - return false; - - return true; -} - -Importable * -Package::import(Handle name) -{ - if (!contents_) - return NULL; - - for (unsigned i = 0; i < contents_->length(); i++) { - Importable *obj = contents_->at(i); - if (obj->isPackage() && Package::cast(obj)->name() == name) - return obj; - if (obj->isModule() && Module::cast(obj)->name() == name) - return obj; - } - - return NULL; -} - -PackageCache::PackageCache(Zone *zone) - : zone_(zone) -{ -} - -bool -PackageCache::initialize() -{ - return true; -} - -void -PackageCache::accept(VirtualObjectVisitor *visitor) -{ - for (size_t i = 0; i < roots_.length(); i++) - visitor->visit(roots_[i].address()); -} - -bool -PackageCache::checkfs(Handle package, PathComponent *path, Importable **out) -{ - AutoFree left(strdup(package->path()->chars())); - AutoFree right(strdup(path->name->chars())); - AutoFree result; - - if (!JoinPaths(zone_, result, *left, *right)) - return false; - - OS::PathType type = OS::InspectPath(*result); - if (type == OS::Path_Folder) { - // If there is a folder matching this path, create a new subpackage, - // and then either return it (if this is the last link), or keep - // trying to import the rest of the path. - Local strpath(zone_, zone_->makeSymbol(*result)); - Local subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal)); - if (!subpackage) - return false; - if (!path->next) { - *out = subpackage; - return true; - } - return import(subpackage, path->next, out); - } - - // Otherwise, look for a file ending in ".sp". - AutoFree filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1)); - if (!*filepath) - return false; - - strcpy(*filepath, *result); - strcat(*filepath, ".sp"); - - type = OS::InspectPath(*filepath); - if (type != OS::Path_File) - return true; - - // Create a new, empty module. - Local strpath(zone_, zone_->makeSymbol(*filepath)); - if (!strpath) - return false; - - Local module(zone_, Module::New(zone_, package, strpath, path->name)); - if (!module || !package->add(zone_, module)) - return false; - - *out = module; - return true; -} - -bool -PackageCache::import(Handle package, PathComponent *path, Importable **out) -{ - // If the package is jailed, none of its imports are visible. - if (package->jailed()) - return true; - - Local obj(zone_, package->import(path->name)); - if (!obj) { - // We couldn't find anything. Try the file system. - if (!checkfs(package, path, out)) - return false; - - // checkfs will keep trying to import, so if it fails, we just - // propagate up. - return true; - } - - // If we found an existing module, or the path has no next link, then - // we can't go any further. - if (obj->is(MapKind_Module) || !path->next) { - *out = obj; - return true; - } - - Local subpackage(zone_, Package::cast(obj)); - return import(subpackage, path->next, out); -} - -bool -PackageCache::findOrAdd(Handle package, PathComponent *path, Importable **out) -{ - // Local rooters should have initialized this, but whatever. - assert(*out == NULL); - - // Try to import locally first. - if (!import(package, path, out)) - return false; - if (*out) - return true; - - // Otherwise, search system roots. - Local root(zone_); - for (size_t i = 0; i < roots_.length(); i++) { - root = roots_[i]; - if (!import(root, path, out)) - return false; - if (*out) - return true; - } - - return true; -} - -PackageCache::~PackageCache() -{ -} +/* + * Copyright (C) 2012 David Anderson + * + * This file is part of SourcePawn. + * + * SourcePawn is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * SourcePawn. If not, see http://www.gnu.org/licenses/. + */ +#include +#include "Zone.h" +#include "Heap.h" +#include "Strings.h" +#include "Modules.h" +#include "Packages.h" +#include "FileSystem.h" +#include "List.h" +#include "Heap-inl.h" +#include "Handles-inl.h" + +using namespace ke; + +Package * +Package::NewNormalized(Zone *zone, Handle parent, Handle path, Handle name, unsigned flags) +{ + Local package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old))); + if (!package) + return NULL; + + // :TODO: assert path, name are atoms. + + package->flags_ = flags; + package->name_ = name; + package->parent_ = parent; + package->path_ = path; + package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL; + + return package; +} + +Package * +Package::New(Zone *zone, Handle parent, const char *path, Handle name, unsigned flags) +{ + Local strpath(zone, zone->makeSymbol(path)); + if (!strpath) + return NULL; + + return Package::NewNormalized(zone, parent, strpath, name, flags); +} + +bool +Package::add(Zone *zone, Handle obj) +{ + Local pkg(zone, this); + + assert(obj->parent() == pkg); + + if (!pkg->contents_) { + pkg->contents_ = List::New(zone); + if (!pkg->contents_) + return false; + } + +#ifndef NDEBUG + // Assert no duplicate names. + for (unsigned i = 0; i < pkg->contents_->length(); i++) + assert(pkg->contents_->at(i)->name() != obj->name()); +#endif + + if (!pkg->contents_->append(zone, obj)) + return false; + + return true; +} + +Importable * +Package::import(Handle name) +{ + if (!contents_) + return NULL; + + for (unsigned i = 0; i < contents_->length(); i++) { + Importable *obj = contents_->at(i); + if (obj->isPackage() && Package::cast(obj)->name() == name) + return obj; + if (obj->isModule() && Module::cast(obj)->name() == name) + return obj; + } + + return NULL; +} + +PackageCache::PackageCache(Zone *zone) + : zone_(zone) +{ +} + +bool +PackageCache::initialize() +{ + return true; +} + +void +PackageCache::accept(VirtualObjectVisitor *visitor) +{ + for (size_t i = 0; i < roots_.length(); i++) + visitor->visit(roots_[i].address()); +} + +bool +PackageCache::checkfs(Handle package, PathComponent *path, Importable **out) +{ + AutoFree left(strdup(package->path()->chars())); + AutoFree right(strdup(path->name->chars())); + AutoFree result; + + if (!JoinPaths(zone_, result, *left, *right)) + return false; + + OS::PathType type = OS::InspectPath(*result); + if (type == OS::Path_Folder) { + // If there is a folder matching this path, create a new subpackage, + // and then either return it (if this is the last link), or keep + // trying to import the rest of the path. + Local strpath(zone_, zone_->makeSymbol(*result)); + Local subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal)); + if (!subpackage) + return false; + if (!path->next) { + *out = subpackage; + return true; + } + return import(subpackage, path->next, out); + } + + // Otherwise, look for a file ending in ".sp". + AutoFree filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1)); + if (!*filepath) + return false; + + strcpy(*filepath, *result); + strcat(*filepath, ".sp"); + + type = OS::InspectPath(*filepath); + if (type != OS::Path_File) + return true; + + // Create a new, empty module. + Local strpath(zone_, zone_->makeSymbol(*filepath)); + if (!strpath) + return false; + + Local module(zone_, Module::New(zone_, package, strpath, path->name)); + if (!module || !package->add(zone_, module)) + return false; + + *out = module; + return true; +} + +bool +PackageCache::import(Handle package, PathComponent *path, Importable **out) +{ + // If the package is jailed, none of its imports are visible. + if (package->jailed()) + return true; + + Local obj(zone_, package->import(path->name)); + if (!obj) { + // We couldn't find anything. Try the file system. + if (!checkfs(package, path, out)) + return false; + + // checkfs will keep trying to import, so if it fails, we just + // propagate up. + return true; + } + + // If we found an existing module, or the path has no next link, then + // we can't go any further. + if (obj->is(MapKind_Module) || !path->next) { + *out = obj; + return true; + } + + Local subpackage(zone_, Package::cast(obj)); + return import(subpackage, path->next, out); +} + +bool +PackageCache::findOrAdd(Handle package, PathComponent *path, Importable **out) +{ + // Local rooters should have initialized this, but whatever. + assert(*out == NULL); + + // Try to import locally first. + if (!import(package, path, out)) + return false; + if (*out) + return true; + + // Otherwise, search system roots. + Local root(zone_); + for (size_t i = 0; i < roots_.length(); i++) { + root = roots_[i]; + if (!import(root, path, out)) + return false; + if (*out) + return true; + } + + return true; +} + +PackageCache::~PackageCache() +{ +}