1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "bin/extensions.h"
6
7#include <stdio.h>
8
9#include "bin/dartutils.h"
10#include "bin/file.h"
11#include "bin/platform.h"
12#include "bin/utils.h"
13#include "include/dart_api.h"
14#include "platform/assert.h"
15#include "platform/globals.h"
16#include "platform/utils.h"
17
18namespace dart {
19namespace bin {
20
21static char PathSeparator() {
22 const char* sep = File::PathSeparator();
23 ASSERT(strlen(sep) == 1);
24 return sep[0];
25}
26
27void* Extensions::MakePathAndResolve(const char* dir, const char* name) {
28 // First try to find the library with a suffix specifying the architecture.
29 {
30 const char* path_components[] = {
31 dir,
32 Platform::LibraryPrefix(),
33 name,
34 "-",
35 Platform::HostArchitecture(), // arm
36 ".",
37 Platform::LibraryExtension(), // so
38 NULL,
39 };
40 const char* library_file = Concatenate(path_components);
41 void* library_handle = LoadExtensionLibrary(library_file);
42 if (library_handle != NULL) {
43 return library_handle;
44 }
45 }
46
47 // Fall back on a library name without the suffix.
48 {
49 const char* path_components[] = {
50 dir,
51 Platform::LibraryPrefix(),
52 name,
53 ".",
54 Platform::LibraryExtension(), // so
55 NULL,
56 };
57 const char* library_file = Concatenate(path_components);
58 return LoadExtensionLibrary(library_file);
59 }
60}
61
62// IMPORTANT: In the absolute path case, do not extract the filename and search
63// for that by passing it to LoadLibrary. That can lead to confusion in
64// which the absolute path is wrong, and a different version of the library is
65// loaded from the standard location.
66void* Extensions::ResolveAbsPathExtension(const char* extension_path) {
67 const char* last_slash = strrchr(extension_path, PathSeparator()) + 1;
68 char* name = Utils::StrDup(last_slash);
69 char* dir = Utils::StrNDup(extension_path, last_slash - extension_path);
70 void* library_handle = MakePathAndResolve(dir, name);
71 free(dir);
72 free(name);
73 return library_handle;
74}
75
76void* Extensions::ResolveExtension(const char* extension_directory,
77 const char* extension_name) {
78 // If the path following dart-ext is an absolute path, then only look for the
79 // library there.
80 if (File::IsAbsolutePath(extension_name)) {
81 return ResolveAbsPathExtension(extension_name);
82 }
83
84 // If the path following dart-ext is just a file name, first look next to
85 // the importing Dart library.
86 void* library_handle =
87 MakePathAndResolve(extension_directory, extension_name);
88 if (library_handle != NULL) {
89 return library_handle;
90 }
91
92 // Then pass the library name down to the platform. E.g. dlopen will do its
93 // own search in standard search locations.
94 return MakePathAndResolve("", extension_name);
95}
96
97Dart_Handle Extensions::LoadExtension(const char* extension_directory,
98 const char* extension_name,
99 Dart_Handle parent_library) {
100 void* library_handle = ResolveExtension(extension_directory, extension_name);
101 if (library_handle == NULL) {
102 return GetError();
103 }
104
105 const char* extension = extension_name;
106 if (File::IsAbsolutePath(extension_name)) {
107 extension = strrchr(extension_name, PathSeparator()) + 1;
108 }
109
110 const char* strings[] = {extension, "_Init", NULL};
111 const char* init_function_name = Concatenate(strings);
112 void* init_function = ResolveSymbol(library_handle, init_function_name);
113 Dart_Handle result = GetError();
114 if (Dart_IsError(result)) {
115 return result;
116 }
117 ASSERT(init_function != NULL);
118 typedef Dart_Handle (*InitFunctionType)(Dart_Handle import_map);
119 InitFunctionType fn = reinterpret_cast<InitFunctionType>(init_function);
120 return (*fn)(parent_library);
121}
122
123// Concatenates a NULL terminated array of strings.
124// The returned string is scope allocated.
125const char* Extensions::Concatenate(const char** strings) {
126 int size = 1; // null termination.
127 for (int i = 0; strings[i] != NULL; i++) {
128 size += strlen(strings[i]);
129 }
130 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(size));
131 int index = 0;
132 for (int i = 0; strings[i] != NULL; i++) {
133 index += snprintf(result + index, size - index, "%s", strings[i]);
134 }
135 ASSERT(index == size - 1);
136 ASSERT(result[size - 1] == '\0');
137 return result;
138}
139
140} // namespace bin
141} // namespace dart
142