mirror of https://gitlab.com/nakst/essence
scripting engine: err type
This commit is contained in:
parent
690ff25688
commit
28a680f8fc
|
@ -163,6 +163,42 @@ void *FileLoad(const char *path, size_t *length) {
|
|||
return EsFileReadAll(path, -1, length);
|
||||
}
|
||||
|
||||
#define RETURN_ERROR(error) do { MakeError(context, returnValue, error); return EXTCALL_RETURN_ERR_ERROR; } while (0)
|
||||
|
||||
void MakeError(ExecutionContext *context, Value *returnValue, EsError error) {
|
||||
const char *text = nullptr;
|
||||
|
||||
if (error == ES_ERROR_OPERATION_BLOCKED) text = "OPERATION_BLOCKED";
|
||||
if (error == ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS) text = "ACCESS_NOT_WITHIN_FILE_BOUNDS";
|
||||
if (error == ES_ERROR_DIRECTORY_NOT_EMPTY) text = "DIRECTORY_NOT_EMPTY";
|
||||
if (error == ES_ERROR_NODE_DELETED) text = "NODE_DELETED";
|
||||
if (error == ES_ERROR_FILE_TOO_LARGE) text = "FILE_TOO_LARGE";
|
||||
if (error == ES_ERROR_DRIVE_FULL) text = "DRIVE_FULL";
|
||||
if (error == ES_ERROR_CORRUPT_DATA) text = "CORRUPT_DATA";
|
||||
if (error == ES_ERROR_INVALID_NAME) text = "INVALID_NAME";
|
||||
if (error == ES_ERROR_FILE_ON_READ_ONLY_VOLUME) text = "FILE_ON_READ_ONLY_VOLUME";
|
||||
if (error == ES_ERROR_PATH_NOT_WITHIN_MOUNTED_VOLUME) text = "PATH_NOT_WITHIN_MOUNTED_VOLUME";
|
||||
if (error == ES_ERROR_PATH_NOT_TRAVERSABLE) text = "PATH_NOT_TRAVERSABLE";
|
||||
if (error == ES_ERROR_DEVICE_REMOVED) text = "DEVICE_REMOVED";
|
||||
if (error == ES_ERROR_INCORRECT_NODE_TYPE) text = "INCORRECT_NODE_TYPE";
|
||||
if (error == ES_ERROR_FILE_DOES_NOT_EXIST) text = "FILE_DOES_NOT_EXIST";
|
||||
if (error == ES_ERROR_VOLUME_MISMATCH) text = "VOLUME_MISMATCH";
|
||||
if (error == ES_ERROR_TARGET_WITHIN_SOURCE) text = "TARGET_WITHIN_SOURCE";
|
||||
if (error == ES_ERROR_UNKNOWN) text = "UNKNOWN";
|
||||
if (error == ES_ERROR_ALREADY_EXISTS) text = "ALREADY_EXISTS";
|
||||
if (error == ES_ERROR_CANCELLED) text = "CANCELLED";
|
||||
if (error == ES_ERROR_INSUFFICIENT_RESOURCES) text = "INSUFFICIENT_RESOURCES";
|
||||
if (error == ES_ERROR_PERMISSION_NOT_GRANTED) text = "PERMISSION_NOT_GRANTED";
|
||||
if (error == ES_ERROR_UNSUPPORTED) text = "UNSUPPORTED";
|
||||
if (error == ES_ERROR_HARDWARE_FAILURE) text = "HARDWARE_FAILURE";
|
||||
|
||||
if (text) {
|
||||
RETURN_STRING_COPY(text, EsCStringLength(text));
|
||||
} else {
|
||||
returnValue->i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CoroutineState *ExternalCoroutineWaitAny(ExecutionContext *context) {
|
||||
(void) context;
|
||||
EsAssert(false); // TODO.
|
||||
|
@ -173,21 +209,21 @@ int ExternalLog(ExecutionContext *context, Value *returnValue) {
|
|||
(void) returnValue;
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
AddLogOutput(scriptInstance, entryText, entryBytes);
|
||||
return 1;
|
||||
return EXTCALL_NO_RETURN;
|
||||
}
|
||||
|
||||
int ExternalLogOpenGroup(ExecutionContext *context, Value *returnValue) {
|
||||
(void) returnValue;
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
AddLogOpenGroup(scriptInstance, entryText, entryBytes);
|
||||
return 1;
|
||||
return EXTCALL_NO_RETURN;
|
||||
}
|
||||
|
||||
int ExternalLogClose(ExecutionContext *context, Value *returnValue) {
|
||||
(void) context;
|
||||
(void) returnValue;
|
||||
AddLogClose(scriptInstance);
|
||||
return 1;
|
||||
return EXTCALL_NO_RETURN;
|
||||
}
|
||||
|
||||
int ExternalTextFormat(ExecutionContext *context, Value *returnValue, const char *mode) {
|
||||
|
@ -197,7 +233,7 @@ int ExternalTextFormat(ExecutionContext *context, Value *returnValue, const char
|
|||
context->heap[index].bytes = EsStringFormat(buffer, 16, "%z", mode);
|
||||
context->heap[index].text = buffer;
|
||||
returnValue->i = index;
|
||||
return 3;
|
||||
return EXTCALL_RETURN_MANAGED;
|
||||
}
|
||||
|
||||
int ExternalTextColorError (ExecutionContext *context, Value *returnValue) { return ExternalTextFormat(context, returnValue, "\a#DB002A]"); }
|
||||
|
@ -218,25 +254,25 @@ int ExternalSystemSleepMs(ExecutionContext *context, Value *returnValue) {
|
|||
if (context->c->stackPointer < 1) return -1;
|
||||
int64_t ms = context->c->stack[--context->c->stackPointer].i;
|
||||
if (ms > 0) EsSleep(ms);
|
||||
return 1;
|
||||
return EXTCALL_NO_RETURN;
|
||||
}
|
||||
|
||||
int ExternalSystemGetHostName(ExecutionContext *context, Value *returnValue) {
|
||||
(void) context;
|
||||
RETURN_STRING_COPY("Essence", 7);
|
||||
return 3;
|
||||
return EXTCALL_RETURN_MANAGED;
|
||||
}
|
||||
|
||||
int ExternalSystemRunningAsAdministrator(ExecutionContext *context, Value *returnValue) {
|
||||
(void) context;
|
||||
returnValue->i = 0;
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalSystemGetProcessorCount(ExecutionContext *context, Value *returnValue) {
|
||||
(void) context;
|
||||
returnValue->i = EsSystemGetOptimalWorkQueueThreadCount();
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalRandomInt(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -246,22 +282,21 @@ int ExternalRandomInt(ExecutionContext *context, Value *returnValue) {
|
|||
if (max < min) { PrintError4(context, 0, "RandomInt() called with maximum limit (%ld) less than the minimum limit (%ld).\n", max, min); return 0; }
|
||||
returnValue->i = EsRandomU64() % (max - min + 1) + min;
|
||||
context->c->stackPointer -= 2;
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalPathCreateDirectory(ExecutionContext *context, Value *returnValue) {
|
||||
(void) returnValue;
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
EsError error = EsPathCreate(entryText, entryBytes, ES_NODE_DIRECTORY, false);
|
||||
returnValue->i = error == ES_SUCCESS || error == ES_ERROR_ALREADY_EXISTS;
|
||||
return 2;
|
||||
if (error == ES_SUCCESS || error == ES_ERROR_ALREADY_EXISTS) return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
int ExternalPathExists(ExecutionContext *context, Value *returnValue) {
|
||||
(void) returnValue;
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
returnValue->i = EsPathExists(entryText, entryBytes) ? 1 : 0;
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalPathIsFile(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -270,7 +305,7 @@ int ExternalPathIsFile(ExecutionContext *context, Value *returnValue) {
|
|||
EsNodeType type;
|
||||
returnValue->i = EsPathExists(entryText, entryBytes, &type) ? 1 : 0;
|
||||
if (type != ES_NODE_FILE) returnValue->i = 0;
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalPathIsDirectory(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -279,44 +314,46 @@ int ExternalPathIsDirectory(ExecutionContext *context, Value *returnValue) {
|
|||
EsNodeType type;
|
||||
returnValue->i = EsPathExists(entryText, entryBytes, &type) ? 1 : 0;
|
||||
if (type != ES_NODE_DIRECTORY) returnValue->i = 0;
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalPathIsLink(ExecutionContext *context, Value *returnValue) {
|
||||
(void) returnValue;
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
returnValue->i = 0;
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalPathMove(ExecutionContext *context, Value *returnValue) {
|
||||
(void) returnValue;
|
||||
STACK_POP_STRING_2(entryText, entryBytes, entry2Text, entry2Bytes);
|
||||
returnValue->i = EsPathMove(entryText, entryBytes, entry2Text, entry2Bytes) == ES_SUCCESS;
|
||||
return 2;
|
||||
EsError error = EsPathMove(entryText, entryBytes, entry2Text, entry2Bytes);
|
||||
if (error != ES_SUCCESS) RETURN_ERROR(error);
|
||||
return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalPathDelete(ExecutionContext *context, Value *returnValue) {
|
||||
(void) returnValue;
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
returnValue->i = EsPathDelete(entryText, entryBytes) == ES_SUCCESS;
|
||||
return 2;
|
||||
return EXTCALL_RETURN_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalFileReadAll(ExecutionContext *context, Value *returnValue) {
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
returnValue->i = 0;
|
||||
size_t length = 0;
|
||||
void *data = EsFileReadAll(entryText, entryBytes, &length); // Free with EsHeapFree.
|
||||
if (!data) return 3;
|
||||
EsError error;
|
||||
void *data = EsFileReadAll(entryText, entryBytes, &length, &error); // Free with EsHeapFree.
|
||||
if (!data) RETURN_ERROR(error);
|
||||
RETURN_STRING_NO_COPY((char *) data, length);
|
||||
return 3;
|
||||
return EXTCALL_RETURN_ERR_MANAGED;
|
||||
}
|
||||
|
||||
int ExternalFileWriteAll(ExecutionContext *context, Value *returnValue) {
|
||||
STACK_POP_STRING_2(entryText, entryBytes, entry2Text, entry2Bytes);
|
||||
returnValue->i = EsFileWriteAll(entryText, entryBytes, entry2Text, entry2Bytes) == ES_SUCCESS;
|
||||
return 2;
|
||||
EsError error = EsFileWriteAll(entryText, entryBytes, entry2Text, entry2Bytes);
|
||||
if (error != ES_SUCCESS) RETURN_ERROR(error);
|
||||
return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalFileAppend(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -325,25 +362,34 @@ int ExternalFileAppend(ExecutionContext *context, Value *returnValue) {
|
|||
EsFileInformation information = EsFileOpen(entryText, entryBytes, ES_FILE_WRITE);
|
||||
|
||||
if (information.error == ES_SUCCESS) {
|
||||
returnValue->i = EsFileWriteSync(information.handle, information.size, entry2Bytes, entry2Text);
|
||||
EsError error = EsFileWriteSync(information.handle, information.size, entry2Bytes, entry2Text);
|
||||
EsHandleClose(information.handle);
|
||||
|
||||
if (ES_CHECK_ERROR(error)) {
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
} else {
|
||||
RETURN_ERROR(information.error);
|
||||
}
|
||||
|
||||
return 2;
|
||||
return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalFileGetSize(ExecutionContext *context, Value *returnValue) {
|
||||
STACK_POP_STRING(entryText, entryBytes);
|
||||
EsDirectoryChild information;
|
||||
bool exists = EsPathQueryInformation(entryText, entryBytes, &information);
|
||||
returnValue->i = exists && information.type == ES_NODE_FILE ? information.fileSize : -1;
|
||||
return 2;
|
||||
if (!exists) RETURN_ERROR(ES_ERROR_FILE_DOES_NOT_EXIST);
|
||||
if (information.type != ES_NODE_FILE) RETURN_ERROR(ES_ERROR_INCORRECT_NODE_TYPE);
|
||||
returnValue->i = information.fileSize;
|
||||
return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||
}
|
||||
|
||||
int ExternalFileCopy(ExecutionContext *context, Value *returnValue) {
|
||||
STACK_POP_STRING_2(entryText, entryBytes, entry2Text, entry2Bytes);
|
||||
returnValue->i = EsFileCopy(entryText, entryBytes, entry2Text, entry2Bytes) == ES_SUCCESS;
|
||||
return 2;
|
||||
EsError error = EsFileCopy(entryText, entryBytes, entry2Text, entry2Bytes);
|
||||
if (error != ES_SUCCESS) RETURN_ERROR(error);
|
||||
return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||
}
|
||||
|
||||
int External_DirectoryInternalStartIteration(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -351,9 +397,9 @@ int External_DirectoryInternalStartIteration(ExecutionContext *context, Value *r
|
|||
EsHeapFree(directoryIterationBuffer);
|
||||
EsError error;
|
||||
directoryIterationBuffer = EsDirectoryEnumerateChildren(entryText, entryBytes, &directoryIterationBufferCount, &error);
|
||||
returnValue->i = error == ES_SUCCESS ? 1 : 0;
|
||||
directoryIterationBufferPosition = 0;
|
||||
return 2;
|
||||
if (error == ES_SUCCESS) return EXTCALL_RETURN_ERR_UNMANAGED;
|
||||
RETURN_ERROR(error);
|
||||
}
|
||||
|
||||
int External_DirectoryInternalEndIteration(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -363,7 +409,7 @@ int External_DirectoryInternalEndIteration(ExecutionContext *context, Value *ret
|
|||
directoryIterationBuffer = nullptr;
|
||||
directoryIterationBufferPosition = 0;
|
||||
directoryIterationBufferCount = 0;
|
||||
return 1;
|
||||
return EXTCALL_NO_RETURN;
|
||||
}
|
||||
|
||||
int External_DirectoryInternalNextIteration(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -377,7 +423,7 @@ int External_DirectoryInternalNextIteration(ExecutionContext *context, Value *re
|
|||
directoryIterationBufferPosition++;
|
||||
}
|
||||
|
||||
return 3;
|
||||
return EXTCALL_RETURN_MANAGED;
|
||||
}
|
||||
|
||||
int ExternalOpenDocumentEnumerate(ExecutionContext *context, Value *returnValue) {
|
||||
|
@ -408,7 +454,7 @@ int ExternalOpenDocumentEnumerate(ExecutionContext *context, Value *returnValue)
|
|||
EsAssert(!buffer.error);
|
||||
returnValue->i = index;
|
||||
|
||||
return 3;
|
||||
return EXTCALL_RETURN_MANAGED;
|
||||
}
|
||||
|
||||
#define EXTERNAL_STUB(name) int name(ExecutionContext *, Value *) { EsPrint("Unimplemented " #name "\n"); EsAssert(false); return -1; }
|
||||
|
@ -774,6 +820,31 @@ void AddREPLResult(ExecutionContext *context, EsElement *parent, Node *type, Val
|
|||
} else {
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, EsStyleIntern(&styleOutputParagraphItalic), EsLiteral("Binary data string.\n"));
|
||||
}
|
||||
} else if (type->type == T_ERR) {
|
||||
if (value.i) {
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||
HeapEntry *entry = &context->heap[value.i];
|
||||
|
||||
if (entry->success) {
|
||||
if (type->firstChild->type == T_VOID) {
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, EsStyleIntern(&styleOutputParagraphItalic),
|
||||
EsLiteral("Success.\n"));
|
||||
} else {
|
||||
AddREPLResult(context, parent, type->firstChild, entry->errorValue);
|
||||
}
|
||||
} else {
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) entry->errorValue.i);
|
||||
const char *valueText;
|
||||
size_t valueBytes;
|
||||
ScriptHeapEntryToString(context, &context->heap[entry->errorValue.i], &valueText, &valueBytes);
|
||||
char buffer[100];
|
||||
size_t bytes = EsStringFormat(buffer, sizeof(buffer), "Error: %s.\n", valueBytes, valueText);
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, EsStyleIntern(&styleOutputParagraphItalic), buffer, bytes);
|
||||
}
|
||||
} else {
|
||||
EsTextDisplayCreate(parent, ES_CELL_H_FILL, EsStyleIntern(&styleOutputParagraphItalic),
|
||||
EsLiteral("Error: UNKNOWN.\n"));
|
||||
}
|
||||
} else if (type->type == T_LIST && type->firstChild->type == T_STRUCT) {
|
||||
EsAssert(context->heapEntriesAllocated > (uint64_t) value.i);
|
||||
HeapEntry *listEntry = &context->heap[value.i];
|
||||
|
|
|
@ -2965,10 +2965,11 @@ int ScrollPane::ReceivedMessage(EsMessage *message) {
|
|||
if (verticalScrollBarWillShow) message->measure.width += bar[1]->style->preferredWidth;
|
||||
return ES_HANDLED;
|
||||
} else if (message->type == ES_MSG_SCROLL_WHEEL) {
|
||||
double oldPosition0 = position[0];
|
||||
double oldPosition1 = position[1];
|
||||
SetPosition(0, position[0] + 60 * message->scrollWheel.dx / ES_SCROLL_WHEEL_NOTCH, true);
|
||||
SetPosition(1, position[1] - 60 * message->scrollWheel.dy / ES_SCROLL_WHEEL_NOTCH, true);
|
||||
if (message->scrollWheel.dx && mode[0]) return ES_HANDLED;
|
||||
if (message->scrollWheel.dy && mode[1]) return ES_HANDLED;
|
||||
if (oldPosition0 != position[0] || oldPosition1 != position[1]) return ES_HANDLED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -119,12 +119,12 @@ void PortBusybox() {
|
|||
str version = "1.33.1";
|
||||
|
||||
if SystemGetHostName() == "Darwin" {
|
||||
SystemSetEnvironmentVariable("PATH", "/usr/local/opt/gnu-sed/libexec/gnubin:" + SystemGetEnvironmentVariable("PATH"));
|
||||
assert SystemSetEnvironmentVariable("PATH", "/usr/local/opt/gnu-sed/libexec/gnubin:" + SystemGetEnvironmentVariable("PATH"):assert());
|
||||
}
|
||||
|
||||
get_source.Get("https://www.busybox.net/downloads/busybox-%version%.tar.bz2", "busybox-%version%",
|
||||
"12cec6bd2b16d8a9446dd16130f2b92982f1819f6e1c5f5887b6db03f5660d28");
|
||||
str[] config = StringSplitByCharacter(FileReadAll("ports/busybox/config"), "\n", true);
|
||||
str[] config = StringSplitByCharacter(FileReadAll("ports/busybox/config"):assert(), "\n", true);
|
||||
config:insert("CONFIG_BUSYBOX_EXEC_PATH=\"%posixPrefix%/bin/busybox\"", 34);
|
||||
config:insert("CONFIG_SYSROOT=\"%posixDestDir%\"", 51);
|
||||
assert FileWriteAll("bin/source/.config", StringJoin(config, "\n", false));
|
||||
|
@ -198,10 +198,10 @@ void PortGCC() {
|
|||
|
||||
if buildCross {
|
||||
// Modify the path.
|
||||
str path = compilerPath + ":" + SystemGetEnvironmentVariable("PATH");
|
||||
SystemSetEnvironmentVariable("PATH", path);
|
||||
str path = compilerPath + ":" + SystemGetEnvironmentVariable("PATH"):assert();
|
||||
assert SystemSetEnvironmentVariable("PATH", path);
|
||||
assert !StringContains(path, "::");
|
||||
assert SystemGetEnvironmentVariable("PATH") == path;
|
||||
assert SystemGetEnvironmentVariable("PATH"):assert() == path;
|
||||
|
||||
// Get the brew library path if we're running on Darwin.
|
||||
str libraryPath = "";
|
||||
|
@ -335,7 +335,7 @@ void PortGCC() {
|
|||
];
|
||||
|
||||
for str variable in variables {
|
||||
SystemSetEnvironmentVariable(variable, "yes");
|
||||
assert SystemSetEnvironmentVariable(variable, "yes");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
514
util/script.c
514
util/script.c
File diff suppressed because it is too large
Load Diff
|
@ -58,11 +58,11 @@ void Start() {
|
|||
}
|
||||
|
||||
void GenerateOVF() {
|
||||
str[] template = StringSplitByCharacter(FileReadAll("util/automation/template.ovf"), "$", true);
|
||||
str[] template = StringSplitByCharacter(FileReadAll("util/automation/template.ovf"):assert(), "$", true);
|
||||
assert template:len() == 5;
|
||||
str uuid1 = UUIDGenerate();
|
||||
str uuid2 = UUIDGenerate();
|
||||
int driveSize = FileGetSize("bin/drive");
|
||||
int driveSize = FileGetSize("bin/drive"):assert();
|
||||
assert driveSize > 0;
|
||||
str result = template[0] + "%driveSize%" + template[1] + uuid1 + template[2] + uuid2 + template[3] + uuid1 + template[4];
|
||||
assert FileWriteAll("bin/ova/Essence.ovf", result);
|
||||
|
@ -198,7 +198,7 @@ void AutomationBuildMinimal() {
|
|||
|
||||
void AutomationRunTests() {
|
||||
Setup(true);
|
||||
str[] buildConfig = StringSplitByCharacter(FileReadAll("bin/build_config.ini"), "\n", true);
|
||||
str[] buildConfig = StringSplitByCharacter(FileReadAll("bin/build_config.ini"):assert(), "\n", true);
|
||||
buildConfig:find_and_delete("automated_build=1");
|
||||
assert FileWriteAll("bin/build_config.ini", StringJoin(buildConfig, "\n", false));
|
||||
assert FileWriteAll("bin/config.ini", "Flag.ENABLE_POSIX_SUBSYSTEM=1\n");
|
||||
|
|
Loading…
Reference in New Issue