#include <sstream>
#include <fstream>
#include <memory>
+#include <algorithm>
#include <dirent.h>
#include <sys/stat.h>
#undef LAUNCHER_PATH
#endif
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR '/'
+#endif
+
+static std::string ConcatPath(const std::string& path1, const std::string& path2)
+{
+ std::string path(path1);
+ if (path.back() == PATH_SEPARATOR)
+ {
+ path.append(path2);
+ }
+ else
+ {
+ path += PATH_SEPARATOR;
+ path.append(path2);
+ }
+
+ return path;
+}
+static void AppendPath(std::string& path1, const std::string& path2)
+{
+ if (path1.back() == PATH_SEPARATOR)
+ {
+ path1.append(path2);
+ }
+ else
+ {
+ path1 += PATH_SEPARATOR;
+ path1.append(path2);
+ }
+}
+
static std::string AbsolutePath(const std::string& path)
{
std::string absPath;
static std::string Basename(const std::string& path)
{
- auto pos = path.find_last_of('/');
+ auto pos = path.find_last_of(PATH_SEPARATOR);
if (pos != std::string::npos)
{
return path.substr(0, pos);
return path;
}
+static bool EndWithIC(const std::string& str1, const std::string& str2, std::string& filename)
+{
+ std::string::size_type len1 = str1.length();
+ std::string::size_type len2 = str2.length();
+ if (len2 > len1) return false;
+
+ int i = 0;
+ bool result = std::all_of(str1.cend() - len2, str1.end(),
+ [&i, &str2] (char x) {
+ return std::tolower(x) == std::tolower(str2[i++]);
+ });
+ if (result)
+ {
+ filename = str1.substr(0, len1 - len2);
+ }
+ return result;
+}
+
static std::string AssembliesInDirectory(const char *directory)
{
- const char * const nativeImageExtension = ".ni";
- const char * const tpaExtensions[] = {".dll", ".exe"};
- int niExtensionSize = strlen(nativeImageExtension);
- int directoryPathSize = strlen(directory);
+ const std::string ni = ".ni";
+ const std::string tpaExtensions[] =
+ {".ni.dll", ".dll", ".ni.exe", ".exe"};
+ const bool tpaExtensions_ni[] =
+ {true, false, true, false};
std::string tpaList;
return std::string();
}
- std::map<std::pair<std::string, std::string>, bool> addedAssemblies;
+ std::set<std::string> addedAssemblies;
struct dirent *entry;
- while ((entry = readdir(dir)) != nullptr)
+
+ int tpaCount = sizeof(tpaExtensions) / sizeof(tpaExtensions[0]);
+ for (int i=0; i<tpaCount; i++)
{
- switch (entry->d_type)
- {
- case DT_REG: break;
- case DT_LNK:
- case DT_UNKNOWN:
- {
- std::string fullname;
- fullname.append(directory);
- fullname.append("/");
- fullname.append(entry->d_name);
-
- struct stat sb;
- if (stat(fullname.c_str(), &sb) == -1)
- continue;
-
- if (!S_ISREG(sb.st_mode))
- continue;
- }
- break;
- default:
- continue;
- }
+ const std::string& ext = tpaExtensions[i];
+ bool isNativeExt = tpaExtensions_ni[i];
- // Check the extension.
- std::string filename(entry->d_name);
- int extPos = filename.find_last_of('.');
- if (extPos <= 0) continue;
- bool notUsedExtension = true;
- for (auto ext : tpaExtensions)
+ while ((entry = readdir(dir)) != nullptr)
{
- int extLength = strlen(ext);
-
- if (filename.compare(extPos, extLength, ext) == 0)
+ switch (entry->d_type)
{
- notUsedExtension = false;
- break;
+ case DT_REG: break;
+ case DT_LNK:
+ case DT_UNKNOWN:
+ {
+ std::string fullname;
+ fullname.append(directory);
+ fullname += PATH_SEPARATOR;
+ fullname.append(entry->d_name);
+
+ struct stat sb;
+ if (stat(fullname.c_str(), &sb) == -1)
+ continue;
+
+ if (!S_ISREG(sb.st_mode))
+ continue;
+ }
+ break;
+ default:
+ continue;
}
- }
- if (notUsedExtension) continue;
- std::string filenameWithoutExt;
- bool isNativeImage = extPos > niExtensionSize ?
- filename.compare(extPos-niExtensionSize, niExtensionSize, nativeImageExtension) == 0 : false;
- if (isNativeImage)
- {
- filenameWithoutExt = filename.substr(0, extPos-niExtensionSize);
- }
- else
- {
- filenameWithoutExt = filename.substr(0, extPos);
- }
- std::string ext = filename.substr(extPos);
+ // Check the extension.
+ std::string filename(entry->d_name);
+ std::string filenameWithoutExt;
+ if (!EndWithIC(filename, ext, filenameWithoutExt))
+ continue;
- std::pair<std::string, std::string> key(filenameWithoutExt, ext);
- if (addedAssemblies.count(key))
- {
- isNativeImage = isNativeImage || addedAssemblies[key];
- }
- addedAssemblies[key] = isNativeImage;
- }
+ if (!isNativeExt)
+ {
+ EndWithIC(filenameWithoutExt, ni, filenameWithoutExt);
+ }
- for (auto pair : addedAssemblies)
- {
- tpaList.append(directory);
- if (directory[directoryPathSize-1] != '/')
- tpaList.append("/");
- tpaList.append(pair.first.first);
- if (pair.second)
- {
- tpaList.append(nativeImageExtension);
+ if (addedAssemblies.find(filenameWithoutExt) == addedAssemblies.end())
+ {
+ addedAssemblies.insert(filenameWithoutExt);
+ std::string assembly;
+ assembly.append(directory);
+ assembly += PATH_SEPARATOR;
+ assembly.append(filename);
+ _DBG("TPA : %s", assembly.c_str());
+ tpaList += assembly + ':';
+ }
}
- tpaList.append(pair.first.second);
- tpaList.append(":");
- _DBG("TPA : %s/%s%s", directory, pair.first.first.c_str(), pair.first.second.c_str());
+ rewinddir(dir);
}
closedir(dir);
}
}
-void Launcher::Launch(const string& exe_path, int argc, char *argv[])
+void Launcher::Launch(const string& exe_path, const string& app_root, int argc, char *argv[])
{
std::string bin_path = Basename(AbsolutePath(exe_path));
- std::string app_home = Basename(bin_path);
- std::string lib_path = app_home + "/lib";
+ std::string lib_path = ConcatPath(AbsolutePath(app_root), "lib");
std::string app_path = bin_path + ":" + lib_path;
std::string app_ni_path = app_path;
std::string nativeDllSearchDirectories = NativeDllSearchDirectories + app_path;
auto on_requested = [&launcher]()
{
};
- auto on_executed = [&launcher](const std::string& path, int argc, char *argv[])
+ auto on_executed = [&launcher](const std::string& path, const std::string& app_root, int argc, char *argv[])
{
_DBG("EXECUTE %s", path.c_str());
- launcher->Launch(path, argc, argv);
+ launcher->Launch(path, app_root, argc, argv);
};
std::unique_ptr<Waiter> waiter(new Waiter(on_prepare, on_requested, on_executed));
waiter->WaitToLaunching(argc, argv);