src/Packages.cpp
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 00:46:29 2013 +0100 (2013-06-10)
changeset 262 c4b1341297e5
parent 256 3c184218462d
child 263 ba85a47ee414
permissions -rw-r--r--
Fix warnings when building with clang.
dvander@251
     1
/*
dvander@251
     2
 * Copyright (C) 2012 David Anderson
dvander@251
     3
 *
dvander@251
     4
 * This file is part of SourcePawn.
dvander@251
     5
 *
dvander@251
     6
 * SourcePawn is free software: you can redistribute it and/or modify it under
dvander@251
     7
 * the terms of the GNU General Public License as published by the Free
dvander@251
     8
 * Software Foundation, either version 3 of the License, or (at your option)
dvander@251
     9
 * any later version.
dvander@251
    10
 * 
dvander@251
    11
 * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
dvander@251
    12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
dvander@251
    13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
dvander@251
    14
 *
dvander@251
    15
 * You should have received a copy of the GNU General Public License along with
dvander@251
    16
 * SourcePawn. If not, see http://www.gnu.org/licenses/.
dvander@251
    17
 */
dvander@252
    18
#include <string.h>
dvander@251
    19
#include "Zone.h"
dvander@251
    20
#include "Heap.h"
dvander@251
    21
#include "Strings.h"
dvander@251
    22
#include "Modules.h"
dvander@251
    23
#include "Packages.h"
dvander@251
    24
#include "FileSystem.h"
dvander@251
    25
#include "List.h"
dvander@251
    26
#include "Heap-inl.h"
dvander@251
    27
#include "Handles-inl.h"
dvander@251
    28
dvander@251
    29
using namespace ke;
dvander@251
    30
dvander@251
    31
Package *
dvander@251
    32
Package::NewNormalized(Zone *zone, Handle<Package> parent, Handle<String> path, Handle<String> name, unsigned flags)
dvander@251
    33
{
dvander@251
    34
    Local<Package> package(zone, Package::cast(zone->allocate(MapKind_Package, sizeof(Package), Heap::Tenure_Old)));
dvander@251
    35
    if (!package)
dvander@251
    36
        return NULL;
dvander@251
    37
dvander@251
    38
    // :TODO: assert path, name are atoms.
dvander@251
    39
dvander@251
    40
    package->flags_ = flags;
dvander@251
    41
    package->name_ = name;
dvander@251
    42
    package->parent_ = parent;
dvander@251
    43
    package->path_ = path;
dvander@251
    44
    package->nativeIdentity_ = parent ? parent->getNativeIdentity() : NULL;
dvander@251
    45
dvander@251
    46
    return package;
dvander@251
    47
}
dvander@251
    48
dvander@251
    49
Package *
dvander@251
    50
Package::New(Zone *zone, Handle<Package> parent, const char *path, Handle<String> name, unsigned flags)
dvander@251
    51
{
dvander@251
    52
    Local<String> strpath(zone, zone->makeSymbol(path));
dvander@251
    53
    if (!strpath)
dvander@251
    54
        return NULL;
dvander@251
    55
dvander@251
    56
    return Package::NewNormalized(zone, parent, strpath, name, flags);
dvander@251
    57
}
dvander@251
    58
dvander@251
    59
bool
dvander@251
    60
Package::add(Zone *zone, Handle<Importable> obj)
dvander@251
    61
{
dvander@251
    62
    Local<Package> pkg(zone, this);
dvander@251
    63
dvander@251
    64
    assert(obj->parent() == pkg);
dvander@251
    65
dvander@251
    66
    if (!pkg->contents_) {
dvander@251
    67
        pkg->contents_ = List<Importable>::New(zone);
dvander@251
    68
        if (!pkg->contents_)
dvander@251
    69
            return false;
dvander@251
    70
    }
dvander@251
    71
dvander@256
    72
#ifndef NDEBUG
dvander@256
    73
    // Assert no duplicate names.
dvander@256
    74
    for (unsigned i = 0; i < pkg->contents_->length(); i++)
dvander@256
    75
        assert(pkg->contents_->at(i)->name() != obj->name());
dvander@256
    76
#endif
dvander@256
    77
dvander@251
    78
    if (!pkg->contents_->append(zone, obj))
dvander@251
    79
        return false;
dvander@251
    80
dvander@251
    81
    return true;
dvander@251
    82
}
dvander@251
    83
dvander@251
    84
Importable *
dvander@251
    85
Package::import(Handle<String> name)
dvander@251
    86
{
dvander@251
    87
    if (!contents_)
dvander@251
    88
        return NULL;
dvander@251
    89
    
dvander@251
    90
    for (unsigned i = 0; i < contents_->length(); i++) {
dvander@251
    91
        Importable *obj = contents_->at(i);
dvander@251
    92
        if (obj->isPackage() && Package::cast(obj)->name() == name)
dvander@251
    93
            return obj;
dvander@251
    94
        if (obj->isModule() && Module::cast(obj)->name() == name)
dvander@251
    95
            return obj;
dvander@251
    96
    }
dvander@251
    97
dvander@251
    98
    return NULL;
dvander@251
    99
}
dvander@251
   100
dvander@251
   101
PackageCache::PackageCache(Zone *zone)
dvander@251
   102
  : zone_(zone)
dvander@251
   103
{
dvander@251
   104
}
dvander@251
   105
dvander@251
   106
bool
dvander@251
   107
PackageCache::initialize()
dvander@251
   108
{
dvander@251
   109
    return true;
dvander@251
   110
}
dvander@251
   111
dvander@251
   112
void
dvander@251
   113
PackageCache::accept(VirtualObjectVisitor *visitor)
dvander@251
   114
{
dvander@251
   115
    for (size_t i = 0; i < roots_.length(); i++)
dvander@251
   116
        visitor->visit(roots_[i].address());
dvander@251
   117
}
dvander@251
   118
dvander@251
   119
bool
dvander@251
   120
PackageCache::checkfs(Handle<Package> package, PathComponent *path, Importable **out)
dvander@251
   121
{
dvander@251
   122
    AutoFree<char> left(strdup(package->path()->chars()));
dvander@251
   123
    AutoFree<char> right(strdup(path->name->chars()));
dvander@251
   124
    AutoFree<char> result;
dvander@251
   125
dvander@251
   126
    if (!JoinPaths(zone_, result, *left, *right))
dvander@251
   127
        return false;
dvander@251
   128
dvander@251
   129
    OS::PathType type = OS::InspectPath(*result);
dvander@251
   130
    if (type == OS::Path_Folder) {
dvander@251
   131
        // If there is a folder matching this path, create a new subpackage,
dvander@251
   132
        // and then either return it (if this is the last link), or keep
dvander@251
   133
        // trying to import the rest of the path.
dvander@251
   134
        Local<String> strpath(zone_, zone_->makeSymbol(*result));
dvander@251
   135
        Local<Package> subpackage(zone_, Package::NewNormalized(zone_, package, strpath, path->name, Package::Normal));
dvander@251
   136
        if (!subpackage)
dvander@251
   137
            return false;
dvander@251
   138
        if (!path->next) {
dvander@251
   139
            *out = subpackage;
dvander@251
   140
            return true;
dvander@251
   141
        }
dvander@251
   142
        return import(subpackage, path->next, out);
dvander@251
   143
    }
dvander@251
   144
dvander@251
   145
    // Otherwise, look for a file ending in ".sp".
dvander@251
   146
    AutoFree<char> filepath((char *)zone_->malloc(strlen(*result) + strlen(".sp") + 1));
dvander@251
   147
    if (!*filepath)
dvander@251
   148
        return false;
dvander@251
   149
dvander@251
   150
    strcpy(*filepath, *result);
dvander@251
   151
    strcat(*filepath, ".sp");
dvander@251
   152
dvander@251
   153
    type = OS::InspectPath(*filepath);
dvander@251
   154
    if (type != OS::Path_File)
dvander@251
   155
        return true;
dvander@251
   156
dvander@251
   157
    // Create a new, empty module.
dvander@251
   158
    Local<String> strpath(zone_, zone_->makeSymbol(*filepath));
dvander@251
   159
    if (!strpath)
dvander@251
   160
        return false;
dvander@251
   161
dvander@251
   162
    Local<Module> module(zone_, Module::New(zone_, package, strpath, path->name));
dvander@251
   163
    if (!module || !package->add(zone_, module))
dvander@251
   164
        return false;
dvander@251
   165
dvander@251
   166
    *out = module;
dvander@251
   167
    return true;
dvander@251
   168
}
dvander@251
   169
dvander@251
   170
bool
dvander@251
   171
PackageCache::import(Handle<Package> package, PathComponent *path, Importable **out)
dvander@251
   172
{
dvander@251
   173
    // If the package is jailed, none of its imports are visible.
dvander@251
   174
    if (package->jailed())
dvander@251
   175
        return true;
dvander@251
   176
dvander@251
   177
    Local<Importable> obj(zone_, package->import(path->name));
dvander@251
   178
    if (!obj) {
dvander@251
   179
        // We couldn't find anything. Try the file system.
dvander@251
   180
        if (!checkfs(package, path, out))
dvander@251
   181
            return false;
dvander@251
   182
dvander@251
   183
        // checkfs will keep trying to import, so if it fails, we just
dvander@251
   184
        // propagate up.
dvander@251
   185
        return true;
dvander@251
   186
    }
dvander@251
   187
dvander@251
   188
    // If we found an existing module, or the path has no next link, then
dvander@251
   189
    // we can't go any further.
dvander@251
   190
    if (obj->is(MapKind_Module) || !path->next) {
dvander@251
   191
        *out = obj;
dvander@251
   192
        return true;
dvander@251
   193
    }
dvander@251
   194
dvander@251
   195
    Local<Package> subpackage(zone_, Package::cast(obj));
dvander@251
   196
    return import(subpackage, path->next, out);
dvander@251
   197
}
dvander@251
   198
dvander@251
   199
bool
dvander@251
   200
PackageCache::findOrAdd(Handle<Package> package, PathComponent *path, Importable **out)
dvander@251
   201
{
dvander@251
   202
    // Local rooters should have initialized this, but whatever.
dvander@251
   203
    assert(*out == NULL);
dvander@251
   204
dvander@251
   205
    // Try to import locally first.
dvander@251
   206
    if (!import(package, path, out))
dvander@251
   207
        return false;
dvander@251
   208
    if (*out)
dvander@251
   209
        return true;
dvander@251
   210
dvander@251
   211
    // Otherwise, search system roots.
dvander@251
   212
    Local<Package> root(zone_);
dvander@251
   213
    for (size_t i = 0; i < roots_.length(); i++) {
dvander@251
   214
        root = roots_[i];
dvander@251
   215
        if (!import(root, path, out))
dvander@251
   216
            return false;
dvander@251
   217
        if (*out)
dvander@251
   218
            return true;
dvander@251
   219
    }
dvander@251
   220
dvander@251
   221
    return true;
dvander@251
   222
}
dvander@251
   223
dvander@251
   224
PackageCache::~PackageCache()
dvander@251
   225
{
dvander@251
   226
}