Files
nostr_terminal/src/editor.c
T

213 lines
4.4 KiB
C

#include "editor.h"
#include "tui.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static int editor_write_all(int fd, const char *data, size_t len) {
size_t off = 0;
while (off < len) {
ssize_t n = write(fd, data + off, len - off);
if (n < 0) {
if (errno == EINTR) {
continue;
}
return -1;
}
off += (size_t)n;
}
return 0;
}
static char *editor_read_file_malloc(const char *path) {
FILE *fp;
long sz;
char *buf;
size_t nread;
if (!path) {
return NULL;
}
fp = fopen(path, "rb");
if (!fp) {
return NULL;
}
if (fseek(fp, 0, SEEK_END) != 0) {
fclose(fp);
return NULL;
}
sz = ftell(fp);
if (sz <= 0) {
fclose(fp);
return NULL;
}
if (fseek(fp, 0, SEEK_SET) != 0) {
fclose(fp);
return NULL;
}
buf = (char *)malloc((size_t)sz + 1U);
if (!buf) {
fclose(fp);
return NULL;
}
nread = fread(buf, 1U, (size_t)sz, fp);
fclose(fp);
if (nread != (size_t)sz) {
free(buf);
return NULL;
}
buf[nread] = '\0';
return buf;
}
typedef struct {
const char *tmp_path;
const char *editor_env;
} editor_spawn_ctx_t;
static int editor_spawn(void *user) {
editor_spawn_ctx_t *ctx = (editor_spawn_ctx_t *)user;
const char *tmp_path;
const char *editor_env;
pid_t pid;
int status = 0;
if (!ctx || !ctx->tmp_path) {
return -1;
}
tmp_path = ctx->tmp_path;
editor_env = ctx->editor_env;
pid = fork();
if (pid < 0) {
return -1;
}
if (pid == 0) {
if (editor_env && editor_env[0] != '\0') {
char command[2048];
char *argv_sh[4];
if (snprintf(command, sizeof(command), "%s \"%s\"", editor_env, tmp_path) >= (int)sizeof(command)) {
_exit(127);
}
argv_sh[0] = "sh";
argv_sh[1] = "-c";
argv_sh[2] = command;
argv_sh[3] = NULL;
execvp("sh", argv_sh);
_exit(127);
}
{
char command[4096];
char *argv_sh[4];
if (snprintf(command,
sizeof(command),
"vipe < \"%s\" > \"%s.out\" && mv \"%s.out\" \"%s\"",
tmp_path,
tmp_path,
tmp_path,
tmp_path) >= (int)sizeof(command)) {
_exit(127);
}
argv_sh[0] = "sh";
argv_sh[1] = "-c";
argv_sh[2] = command;
argv_sh[3] = NULL;
execvp("sh", argv_sh);
}
{
char *argv_vi[3];
argv_vi[0] = "vi";
argv_vi[1] = (char *)tmp_path;
argv_vi[2] = NULL;
execvp("vi", argv_vi);
}
_exit(127);
}
while (waitpid(pid, &status, 0) < 0) {
if (errno != EINTR) {
break;
}
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
return -1;
}
return 0;
}
static int editor_run_command(const char *tmp_path, const char *editor_env) {
editor_spawn_ctx_t ctx;
if (!tmp_path) {
return -1;
}
ctx.tmp_path = tmp_path;
ctx.editor_env = editor_env;
return nt_run_external_editor(editor_spawn, &ctx);
}
char *editor_launch(const char *initial_content) {
char template_path[] = "/tmp/nt_editor_XXXXXX";
int fd;
char *out = NULL;
const char *editor_env;
fd = mkstemp(template_path);
if (fd < 0) {
return NULL;
}
if (initial_content && initial_content[0] != '\0') {
size_t len = strlen(initial_content);
if (editor_write_all(fd, initial_content, len) != 0) {
close(fd);
unlink(template_path);
return NULL;
}
}
if (close(fd) != 0) {
unlink(template_path);
return NULL;
}
editor_env = getenv("EDITOR");
if (editor_run_command(template_path, editor_env) != 0) {
unlink(template_path);
return NULL;
}
out = editor_read_file_malloc(template_path);
unlink(template_path);
return out;
}