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