<commit_before>#define _XOPEN_SOURCE 600
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include "runes.h"

static void runes_pty_backend_read(uv_work_t *req);
static void runes_pty_backend_got_data(uv_work_t *req, int status);

void runes_pty_backend_spawn_subprocess(RunesTerm *t)
{
    RunesPtyBackend *pty = &t->pty;

    pty->master = posix_openpt(O_RDWR);
    grantpt(pty->master);
    unlockpt(pty->master);
    pty->slave = open(ptsname(pty->master), O_RDWR);

    pty->child_pid = fork();
    if (pty->child_pid) {
        close(pty->slave);
        pty->slave = -1;
    }
    else {
        char *cmd;

        setsid();
        ioctl(pty->slave, TIOCSCTTY, NULL);

        close(pty->master);

        dup2(pty->slave, 0);
        dup2(pty->slave, 1);
        dup2(pty->slave, 2);

        close(pty->slave);

        cmd = t->cmd;
        if (!cmd) {
            cmd = getenv("SHELL");
        }
        if (!cmd) {
            cmd = "/bin/sh";
        }

        /* XXX should use a different TERM value eventually, but for right now
         * screen is compatible enough */
        setenv("TERM", "screen", 1);
        unsetenv("LINES");
        unsetenv("COLUMNS");

        execlp(cmd, cmd, (char *)NULL);
    }
}

void runes_pty_backend_start_loop(RunesTerm *t)
{
    void *data;

    data = malloc(sizeof(RunesLoopData));
    ((RunesLoopData *)data)->req.data = data;
    ((RunesLoopData *)data)->t = t;

    uv_queue_work(
        t->loop, data, runes_pty_backend_read, runes_pty_backend_got_data);
}

void runes_pty_backend_set_window_size(RunesTerm *t)
{
    struct winsize size;

    size.ws_row = t->rows;
    size.ws_col = t->cols;
    size.ws_xpixel = t->xpixel;
    size.ws_ypixel = t->ypixel;
    ioctl(t->pty.master, TIOCSWINSZ, &size);
}

void runes_pty_backend_write(RunesTerm *t, char *buf, size_t len)
{
    write(t->pty.master, buf, len);
}

void runes_pty_backend_request_close(RunesTerm *t)
{
    RunesPtyBackend *pty = &t->pty;

    kill(pty->child_pid, SIGHUP);
}

void runes_pty_backend_cleanup(RunesTerm *t)
{
    RunesPtyBackend *pty = &t->pty;

    close(pty->master);
}

static void runes_pty_backend_read(uv_work_t *req)
{
    RunesLoopData *data = req->data;
    RunesTerm *t = data->t;

    runes_window_backend_request_flush(t);
    t->readlen = read(
        t->pty.master, t->readbuf + t->remaininglen,
        RUNES_READ_BUFFER_LENGTH - t->remaininglen);
}

static void runes_pty_backend_got_data(uv_work_t *req, int status)
{
    RunesLoopData *data = req->data;
    RunesTerm *t = data->t;

    UNUSED(status);

    if (t->readlen > 0) {
        runes_parser_process_string(
            t, t->readbuf, t->readlen + t->remaininglen);
        uv_queue_work(
            t->loop, req, runes_pty_backend_read, runes_pty_backend_got_data);
    }
    else {
        runes_window_backend_request_close(t);
        free(req);
    }
}
<commit_msg>report errors when exec fails<commit_after>#define _XOPEN_SOURCE 600
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include "runes.h"

static void runes_pty_backend_read(uv_work_t *req);
static void runes_pty_backend_got_data(uv_work_t *req, int status);

void runes_pty_backend_spawn_subprocess(RunesTerm *t)
{
    RunesPtyBackend *pty = &t->pty;

    pty->master = posix_openpt(O_RDWR);
    grantpt(pty->master);
    unlockpt(pty->master);
    pty->slave = open(ptsname(pty->master), O_RDWR);

    pty->child_pid = fork();
    if (pty->child_pid) {
        close(pty->slave);
        pty->slave = -1;
    }
    else {
        char *cmd;
        int old_stderr_fd;
        FILE *old_stderr;

        old_stderr_fd = dup(2);
        fcntl(old_stderr_fd, F_SETFD, FD_CLOEXEC);
        old_stderr = fdopen(old_stderr_fd, "w");

        setsid();
        ioctl(pty->slave, TIOCSCTTY, NULL);

        close(pty->master);

        dup2(pty->slave, 0);
        dup2(pty->slave, 1);
        dup2(pty->slave, 2);

        close(pty->slave);

        cmd = t->cmd;
        if (!cmd) {
            cmd = getenv("SHELL");
        }
        if (!cmd) {
            cmd = "/bin/sh";
        }

        /* XXX should use a different TERM value eventually, but for right now
         * screen is compatible enough */
        setenv("TERM", "screen", 1);
        unsetenv("LINES");
        unsetenv("COLUMNS");

        execlp(cmd, cmd, (char *)NULL);

        fprintf(old_stderr, "Couldn't run %s: %s\n", cmd, strerror(errno));
        exit(1);
    }
}

void runes_pty_backend_start_loop(RunesTerm *t)
{
    void *data;

    data = malloc(sizeof(RunesLoopData));
    ((RunesLoopData *)data)->req.data = data;
    ((RunesLoopData *)data)->t = t;

    uv_queue_work(
        t->loop, data, runes_pty_backend_read, runes_pty_backend_got_data);
}

void runes_pty_backend_set_window_size(RunesTerm *t)
{
    struct winsize size;

    size.ws_row = t->rows;
    size.ws_col = t->cols;
    size.ws_xpixel = t->xpixel;
    size.ws_ypixel = t->ypixel;
    ioctl(t->pty.master, TIOCSWINSZ, &size);
}

void runes_pty_backend_write(RunesTerm *t, char *buf, size_t len)
{
    write(t->pty.master, buf, len);
}

void runes_pty_backend_request_close(RunesTerm *t)
{
    RunesPtyBackend *pty = &t->pty;

    kill(pty->child_pid, SIGHUP);
}

void runes_pty_backend_cleanup(RunesTerm *t)
{
    RunesPtyBackend *pty = &t->pty;

    close(pty->master);
}

static void runes_pty_backend_read(uv_work_t *req)
{
    RunesLoopData *data = req->data;
    RunesTerm *t = data->t;

    runes_window_backend_request_flush(t);
    t->readlen = read(
        t->pty.master, t->readbuf + t->remaininglen,
        RUNES_READ_BUFFER_LENGTH - t->remaininglen);
}

static void runes_pty_backend_got_data(uv_work_t *req, int status)
{
    RunesLoopData *data = req->data;
    RunesTerm *t = data->t;

    UNUSED(status);

    if (t->readlen > 0) {
        runes_parser_process_string(
            t, t->readbuf, t->readlen + t->remaininglen);
        uv_queue_work(
            t->loop, req, runes_pty_backend_read, runes_pty_backend_got_data);
    }
    else {
        runes_window_backend_request_close(t);
        free(req);
    }
}

{'fraction_non_alphanumeric': 0.13959143968871596, 'fraction_numerical': 0.004215304798962386, 'mean_word_length': 2.791641057160418, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 102, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '42021', 'n_tokens_mistral': 2374, 'n_tokens_neox': 2387, 'n_words': 426}