-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathjeload.cpp
179 lines (152 loc) · 4.88 KB
/
jeload.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* Copyright 1990-2008, Jsoftware Inc. All rights reserved. */
/* Licensed use only. Any other use is in violation of copyright. */
// utilities for JFE to load JE, initiallize, and run profile sentence
// JFEs are jconsole, jwdw, and jwdp
// TODO: Remove all void* where applicable when other parts of the code start being refactored
#include <filesystem>
#include <string>
#include <stdexcept>
#include <cstdint>
#include <unistd.h>
#include <dlfcn.h>
#include "j.h"
#include "jversion.h"
#include "util/string.hpp"
#ifdef __MACH__
#include <mach-o/dyld.h> // for _NSGetExecutablePath
constexpr std::string_view JDLLNAME{"libj.dylib"};
#else
#include <sys/utsname.h>
constexpr std::string_view JDLLNAME{"libj.so"};
#endif
extern "C" {
static void* hjdll; // handle to J DLL
static J jt;
static JDoType jdo;
static JFreeType jfree;
static JgaType jga;
static JGetLocaleType jgetlocale;
static JGetAType jgeta;
static JSetAType jseta;
std::filesystem::path path;
std::filesystem::path pathdll;
auto
jedo(char const* sentence) -> int {
return jdo(jt, reinterpret_cast<C*>(const_cast<char*>(sentence)));
}
auto
jegeta(I n, char* s) -> A {
return jgeta(jt, n, reinterpret_cast<C*>(s));
}
auto
jeseta(I n, char* name, I x, char* d) -> I {
return jseta(jt, n, reinterpret_cast<C*>(name), x, reinterpret_cast<C*>(d));
}
auto
jefree() -> void {
jfree(jt);
}
auto
jegetlocale() -> char* {
return reinterpret_cast<char*>(jgetlocale(jt));
}
auto
jega(I t, I n, I r, I* s) -> A {
return jga(jt, t, n, r, s);
}
auto
je_load_procedure_addresses(void* hjdll, void* callbacks) -> void {
auto jsm = reinterpret_cast<JSMType>(dlsym(hjdll, "JSM"));
jsm(jt, callbacks);
jdo = reinterpret_cast<JDoType>(dlsym(hjdll, "JDo"));
jfree = reinterpret_cast<JFreeType>(dlsym(hjdll, "JFree"));
jga = reinterpret_cast<JgaType>(dlsym(hjdll, "Jga"));
jgetlocale = reinterpret_cast<JGetLocaleType>(dlsym(hjdll, "JGetLocale"));
jgeta = reinterpret_cast<JGetAType>(dlsym(hjdll, "JGetA"));
jseta = reinterpret_cast<JSetAType>(dlsym(hjdll, "JSetA"));
}
// load JE, Jinit, getprocaddresses, JSM
auto
jeload(void* callbacks) -> J {
hjdll = dlopen(pathdll.c_str(), RTLD_LAZY);
if (!hjdll) {
char* error = dlerror();
printf("ERROR\tCould not open library globally: %s\n", error ? error : "");
return nullptr;
}
jt = static_cast<JST*>(reinterpret_cast<JInitType>(dlsym(hjdll, "JInit"))());
if (!jt) return nullptr;
je_load_procedure_addresses(hjdll, callbacks);
return jt;
}
// set path and pathdll (wpath also set for win)
// WIN arg is 0, Unix arg is argv[0]
auto
jepath(char* arg, char* lib) -> void {
uint32_t const sz = 4000;
// C strings need to be used for POSIX APIs and macOS APIs
auto const arg2 = std::unique_ptr<char[]>(new char[sz]);
auto const arg3 = std::unique_ptr<char[]>(new char[sz]);
// try host dependent way to get path to executable
// use arg if they fail (arg command in PATH won't work)
#ifdef __MACH__
// Returns 0 if path was copied, otherwise -1 if failed.
if (uint32_t len = sz; _NSGetExecutablePath(arg2.get(), &len) != 0) strcat(arg2.get(), arg);
#else
{
auto const n = readlink("/proc/self/exe", arg2, sz);
if (n == -1)
strcpy(arg2, arg);
else
arg2[n] = 0;
}
#endif
// arg2 is path (abs or relative) to executable or soft link
auto const n = readlink(arg2.get(), arg3.get(), sz);
if (n == -1)
strcpy(arg3.get(), arg2.get());
else
arg3[n] = 0;
if ('/' == arg3[0])
path = arg3.get();
else
path = std::filesystem::current_path() / arg3.get();
path.remove_filename();
// remove ./ and backoff ../
path = path.lexically_normal();
pathdll = path / (*lib ? lib : JDLLNAME);
}
// build and run first sentence to set BINPATH, ARGV, and run profile
// arg is command line ready to set in ARGV_z_
// type is 0 normal, 1 -jprofile xxx, 2 ijx basic, 3 nothing
// profile[ARGV_z_=:...[BINPATH=:....
// profile is from BINPATH, ARGV, ijx basic, or nothing
auto
jefirst(int type, char* arg) -> int {
std::string input;
if (type == 0)
input.append("(3 : '0!:0 y')<BINPATH,'/profile.ijs'");
else if (type == 1)
input.append("(3 : '0!:0 y')2{ARGV");
else if (type == 2)
input.append("");
else
input.append("i.0 0");
input.append("[ARGV_z_=:");
input.append(arg);
#if defined(__MACH__)
input.append("[UNAME_z_=:'Darwin'");
#endif
input.append("[BINPATH_z_=:'");
input.append(path);
input.append("'[LIBFILE_z_=:'");
input.append(pathdll);
input.append("'");
// TODO: When jedo is refactored, change this
return jedo(input.c_str());
}
auto
jefail() noexcept(false) -> void {
throw std::invalid_argument("Load library " + std::string(pathdll) + " failed: " + std::string(strerror(errno)));
}
}