Porting to linux
This commit is contained in:
@@ -795,6 +795,7 @@ String SkipToLastSlash(String s);
|
||||
String SkipToLastPeriod(String s);
|
||||
String Copy(Allocator allocator, String string);
|
||||
Int GetSize(Array<String> array);
|
||||
Array<String> Split(Allocator allocator, String string, String delimiter);
|
||||
/*
|
||||
Hash table implementation:
|
||||
Pointers to values
|
||||
|
||||
@@ -46,7 +46,7 @@ struct Process {
|
||||
Process SpawnProcess(String command_line, String working_dir, String write_stdin = {}, Array<String> enviroment = {});
|
||||
bool IsValid(Process *process);
|
||||
void KillProcess(Process *process);
|
||||
String PollStdout(Allocator allocator, Process *process);
|
||||
String PollStdout(Allocator allocator, Process *process, bool force_read);
|
||||
void WriteStdin(Process *process, String string);
|
||||
void CloseStdin(Process *process);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/limits.h>
|
||||
#include <unistd.h>
|
||||
@@ -11,6 +12,9 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <spawn.h>
|
||||
#include <poll.h>
|
||||
|
||||
|
||||
void (*Error)(const char *, ...);
|
||||
|
||||
@@ -212,28 +216,204 @@ FileIter IterateFiles(Allocator alo, String path) {
|
||||
return it;
|
||||
}
|
||||
|
||||
// struct Process {
|
||||
// bool is_valid;
|
||||
// int exit_code;
|
||||
// char platform[6 * 8];
|
||||
//
|
||||
// int64_t view_id; // text editor view
|
||||
// bool scroll_to_end;
|
||||
// };
|
||||
|
||||
struct UnixProcess {
|
||||
pid_t pid;
|
||||
int child_stdout_read;
|
||||
int stdin_write;
|
||||
};
|
||||
|
||||
Array<char *> SplitCommand(Allocator allocator, String command_line) {
|
||||
Array<char *> cmd = {allocator};
|
||||
|
||||
String curr = {};
|
||||
for (int i = 0; i < command_line.len; i += 1) {
|
||||
if (command_line.data[i] == ' ') {
|
||||
if (curr.len > 0) {
|
||||
Add(&cmd, Copy(allocator, curr).data);
|
||||
curr = {};
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (curr.len == 0) {
|
||||
curr.data = command_line.data + i;
|
||||
}
|
||||
curr.len += 1;
|
||||
}
|
||||
|
||||
if (curr.len > 0) {
|
||||
Add(&cmd, Copy(allocator, curr).data);
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
Process SpawnProcess(String command_line, String working_dir, String write_stdin, Array<String> enviroment) {
|
||||
return {};
|
||||
const int PIPE_READ = 0;
|
||||
const int PIPE_WRITE = 1;
|
||||
bool error = false;
|
||||
|
||||
Scratch scratch;
|
||||
Process process = {};
|
||||
UnixProcess *plat = (UnixProcess *)&process.platform;
|
||||
Array<char *> args = SplitCommand(scratch, command_line);
|
||||
Array<char *> env = {scratch};
|
||||
|
||||
For (enviroment) {
|
||||
Add(&env, Copy(scratch, it).data);
|
||||
}
|
||||
|
||||
int stdout_desc[2] = {};
|
||||
int stdin_desc[2] = {};
|
||||
posix_spawn_file_actions_t actions = {};
|
||||
|
||||
if (posix_spawn_file_actions_init(&actions) != 0) {
|
||||
perror("posix_spawn_file_actions_init");
|
||||
return process;
|
||||
}
|
||||
defer {
|
||||
posix_spawn_file_actions_destroy(&actions);
|
||||
};
|
||||
|
||||
if (pipe(stdout_desc) == -1) {
|
||||
perror("pipe");
|
||||
return process;
|
||||
}
|
||||
defer {
|
||||
if (error) {
|
||||
close(stdout_desc[PIPE_READ]);
|
||||
close(stdout_desc[PIPE_WRITE]);
|
||||
} else {
|
||||
close(stdout_desc[PIPE_WRITE]);
|
||||
}
|
||||
};
|
||||
|
||||
if (pipe(stdin_desc) == -1) {
|
||||
perror("pipe");
|
||||
return process;
|
||||
}
|
||||
defer {
|
||||
if (error) {
|
||||
close(stdin_desc[PIPE_READ]);
|
||||
close(stdin_desc[PIPE_WRITE]);
|
||||
} else {
|
||||
close(stdin_desc[PIPE_READ]);
|
||||
}
|
||||
};
|
||||
|
||||
error = posix_spawn_file_actions_addclose(&actions, stdout_desc[PIPE_READ]) != 0;
|
||||
if (error) {
|
||||
perror("posix_spawn_file_actions_addclose");
|
||||
return process;
|
||||
}
|
||||
|
||||
error = posix_spawn_file_actions_adddup2(&actions, stdout_desc[PIPE_WRITE], STDOUT_FILENO) != 0;
|
||||
if (error) {
|
||||
perror("posix_spawn_file_actions_adddup2 STDOUT_FILENO");
|
||||
return process;
|
||||
}
|
||||
|
||||
error = posix_spawn_file_actions_adddup2(&actions, stdout_desc[PIPE_WRITE], STDERR_FILENO) != 0;
|
||||
if (error) {
|
||||
perror("posix_spawn_file_actions_adddup2 STDERR_FILENO");
|
||||
return process;
|
||||
}
|
||||
|
||||
error = posix_spawn_file_actions_addclose(&actions, stdin_desc[PIPE_WRITE]) != 0;
|
||||
if (error) {
|
||||
perror("posix_spawn_file_actions_addclose");
|
||||
return process;
|
||||
}
|
||||
|
||||
error = posix_spawn_file_actions_adddup2(&actions, stdin_desc[PIPE_READ], STDIN_FILENO) != 0;
|
||||
if (error) {
|
||||
perror("posix_spawn_file_actions_adddup2 STDIN_FILENO");
|
||||
return process;
|
||||
}
|
||||
|
||||
pid_t process_pid = 0;
|
||||
error = posix_spawnp(&process_pid, args[0], &actions, NULL, args.data, env.data) != 0;
|
||||
if (error) {
|
||||
perror("failed to create process\n");
|
||||
return process;
|
||||
}
|
||||
|
||||
|
||||
process.is_valid = true;
|
||||
plat->child_stdout_read = stdout_desc[PIPE_READ];
|
||||
plat->stdin_write = stdin_desc[PIPE_WRITE];
|
||||
|
||||
if (write_stdin.len) {
|
||||
WriteStdin(&process, write_stdin);
|
||||
CloseStdin(&process);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
bool IsValid(Process *process) {
|
||||
return false;
|
||||
UnixProcess *plat = (UnixProcess *)&process->platform;
|
||||
if (process->is_valid == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
pid_t result = waitpid(plat->pid, &status, WNOHANG);
|
||||
if (result >= 0) {
|
||||
if (WIFSIGNALED(status) || WIFEXITED(status)) {
|
||||
process->exit_code = WEXITSTATUS(status);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KillProcess(Process *process) {
|
||||
|
||||
Assert(process->is_valid);
|
||||
UnixProcess *plat = (UnixProcess *)process->platform;
|
||||
kill(plat->pid, SIGKILL);
|
||||
process->exit_code = -1;
|
||||
}
|
||||
|
||||
String PollStdout(Allocator allocator, Process *process) {
|
||||
return "";
|
||||
String PollStdout(Allocator allocator, Process *process, bool force_read) {
|
||||
Assert(process->is_valid);
|
||||
UnixProcess *plat = (UnixProcess *)process->platform;
|
||||
|
||||
String result = {};
|
||||
result.data = AllocArray(allocator, char, 16 * 4096);
|
||||
|
||||
pollfd p = {};
|
||||
p.fd = plat->child_stdout_read;
|
||||
p.events = POLLIN;
|
||||
int res = poll(&p, 1, 0);
|
||||
if (res == 1 || force_read) {
|
||||
result.len = read(plat->child_stdout_read, result.data, 4 * 4096);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void WriteStdin(Process *process, String string) {
|
||||
if (string.len == 0) return;
|
||||
Assert(process->is_valid);
|
||||
|
||||
UnixProcess *plat = (UnixProcess *)process->platform;
|
||||
ssize_t size = write(plat->stdin_write, string.data, string.len);
|
||||
|
||||
Assert(size == string.len);
|
||||
}
|
||||
|
||||
void CloseStdin(Process *process) {
|
||||
UnixProcess *plat = (UnixProcess *)process->platform;
|
||||
close(plat->stdin_write);
|
||||
}
|
||||
|
||||
@@ -458,7 +458,7 @@ void KillProcess(Process *process) {
|
||||
process->exit_code = -1;
|
||||
}
|
||||
|
||||
String PollStdout(Allocator allocator, Process *process) {
|
||||
String PollStdout(Allocator allocator, Process *process, bool force_read) {
|
||||
Assert(process->is_valid);
|
||||
Win32Process *p = (Win32Process *)process->platform;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ Style.DrawScrollbar = 1
|
||||
Style.IndentSize = 4
|
||||
Style.FontSize = 15
|
||||
Style.FontFilter = 0
|
||||
Style.Font = "C:/Windows/Fonts/consola.ttf"
|
||||
Style.Font = "/home/krz/text_editor/package/CascadiaMono.ttf"
|
||||
Style.VCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat"
|
||||
Style.TrimWhitespaceOnSave = true
|
||||
Style.ClangFormatOnSave = false
|
||||
|
||||
@@ -63,5 +63,5 @@ Int StyleDrawScrollbar = 1;
|
||||
Int StyleIndentSize = 4;
|
||||
Int StyleFontSize = 15;
|
||||
Int StyleFontFilter = 0;
|
||||
String StyleFont = "C:/Windows/Fonts/consola.ttf";
|
||||
String StyleFont = "/home/krz/text_editor/package/CascadiaMono.ttf";
|
||||
String StyleVCVarsall = "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvars64.bat";
|
||||
@@ -117,8 +117,8 @@ int Lua_KillWindow(lua_State *L) {
|
||||
static void HookLuaForceExit(lua_State *L, lua_Debug *debug) {
|
||||
SDL_PumpEvents();
|
||||
int numkeys = 0;
|
||||
const uint8_t *keys = SDL_GetKeyboardState(&numkeys);
|
||||
if (keys[SDL_SCANCODE_F9] > 0)
|
||||
const bool *keys = SDL_GetKeyboardState(&numkeys);
|
||||
if (keys[SDL_SCANCODE_F9])
|
||||
luaL_error(L, "lua execution got interrupted");
|
||||
}
|
||||
|
||||
|
||||
@@ -5,23 +5,41 @@ Array<Process> ActiveProcesses = {};
|
||||
// and platform independent one
|
||||
Array<String> Enviroment = {};
|
||||
|
||||
struct UnixProcess {
|
||||
pid_t pid;
|
||||
int child_stdout_read;
|
||||
};
|
||||
|
||||
// WARNING: seems that this maybe can't work reliably?
|
||||
// in case of 'git grep a' it's possible that child process spawns it's own
|
||||
// child process and then it won't print anything because it won't have
|
||||
// the appropriate handles. This happens in this case when git grep calls
|
||||
// 'less' program which errors out and doesn't print anything
|
||||
// @todo: maybe I should ask someone smarter about this!
|
||||
|
||||
|
||||
// @todo: rework to fit both linux and windows!
|
||||
void UpdateProcesses() {
|
||||
IterRemove(ActiveProcesses) {
|
||||
IterRemovePrepare(ActiveProcesses);
|
||||
Scratch scratch;
|
||||
String poll = PollStdout(scratch, &it);
|
||||
View *view = GetView({it.view_id});
|
||||
|
||||
String poll = PollStdout(scratch, &it, false);
|
||||
if (poll.len) {
|
||||
Command_Append(view, poll, it.scroll_to_end);
|
||||
}
|
||||
if (!IsValid(&it)) {
|
||||
for (;;) {
|
||||
String poll = PollStdout(scratch, &it, true);
|
||||
if (poll.len) {
|
||||
Command_Append(view, poll, it.scroll_to_end);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Command_Append(view, Format(scratch, "process exited with code: %d\n", it.exit_code), it.scroll_to_end);
|
||||
remove_item = true;
|
||||
}
|
||||
@@ -45,7 +63,7 @@ Buffer *ExecAndWait(Allocator allocator, String cmd, String working_dir, String
|
||||
Buffer *temp_buffer = CreateTempBuffer(allocator, 4096 * 4);
|
||||
for (Process process = SpawnProcess(cmd, working_dir, stdin_string, Enviroment); IsValid(&process);) {
|
||||
Scratch scratch(allocator);
|
||||
String poll = PollStdout(scratch, &process);
|
||||
String poll = PollStdout(scratch, &process, true);
|
||||
if (poll.len) RawAppend(temp_buffer, poll);
|
||||
}
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ int main(int argc, char **argv)
|
||||
SDL_free(sdl_config_path.data);
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) == -1) {
|
||||
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||
ReportErrorf("Couldn't initialize SDL! %s", SDL_GetError());
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user