<commit_before>/*
 * Copyright (C) 2012, 2013
 *     <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "gmqcc.h"
#include <sys/types.h>
#include <sys/stat.h>

opts_cmd_t opts;

const char *task_bins[] = {
    "./gmqcc",
    "./qcvm"
};

/*
 * TODO: Windows version
 * this implements a unique bi-directional popen-like function that
 * allows reading data from both stdout and stderr. And writing to
 * stdin :)
 *
 * Example of use:
 * FILE *handles[3] = task_popen("ls", "-l", "r");
 * if (!handles) { perror("failed to open stdin/stdout/stderr to ls");
 * // handles[0] = stdin
 * // handles[1] = stdout
 * // handles[2] = stderr
 *
 * task_pclose(handles); // to close
 */
#ifndef _WIN32
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <unistd.h>
typedef struct {
    FILE *handles[3];
    int   pipes  [3];

    int stderr_fd;
    int stdout_fd;
    int pid;
} popen_t;

FILE ** task_popen(const char *command, const char *mode) {
    int     inhandle  [2];
    int     outhandle [2];
    int     errhandle [2];
    int     trypipe;

    popen_t *data = (popen_t*)mem_a(sizeof(popen_t));

    /*
     * Parse the command now into a list for execv, this is a pain
     * in the ass.
     */
    char  *line = (char*)command;
    char **argv = NULL;
    {

        while (*line != '\0') {
            while (*line == ' ' || *line == '\t' || *line == '\n')
                *line++ = '\0';
            vec_push(argv, line);

            while (*line != '\0' && *line != ' ' &&
                   *line != '\t' && *line != '\n') line++;
        }
        vec_push(argv, '\0');
    }


    if ((trypipe = pipe(inhandle))  < 0) goto task_popen_error_0;
    if ((trypipe = pipe(outhandle)) < 0) goto task_popen_error_1;
    if ((trypipe = pipe(errhandle)) < 0) goto task_popen_error_2;

    if ((data->pid = fork()) > 0) {
        /* parent */
        close(inhandle  [0]);
        close(outhandle [1]);
        close(errhandle [1]);

        data->pipes  [0] = inhandle [1];
        data->pipes  [1] = outhandle[0];
        data->pipes  [2] = errhandle[0];
        data->handles[0] = fdopen(inhandle [1], "w");
        data->handles[1] = fdopen(outhandle[0], mode);
        data->handles[2] = fdopen(errhandle[0], mode);

        /* sigh */
        if (argv)
            vec_free(argv);
        return data->handles;
    } else if (data->pid == 0) {
        /* child */
        close(inhandle [1]);
        close(outhandle[0]);
        close(errhandle[0]);

        /* see piping documentation for this sillyness :P */
        close(0), dup(inhandle [0]);
        close(1), dup(outhandle[1]);
        close(2), dup(errhandle[1]);

        execvp(*argv, argv);
        exit(EXIT_FAILURE);
    } else {
        /* fork failed */
        goto task_popen_error_3;
    }

task_popen_error_3: close(errhandle[0]), close(errhandle[1]);
task_popen_error_2: close(outhandle[0]), close(outhandle[1]);
task_popen_error_1: close(inhandle [0]), close(inhandle [1]);
task_popen_error_0:

    if (argv)
        vec_free(argv);
    return NULL;
}

int task_pclose(FILE **handles) {
    popen_t *data   = (popen_t*)handles;
    int      status = 0;

    close(data->pipes[0]); /* stdin  */
    close(data->pipes[1]); /* stdout */
    close(data->pipes[2]); /* stderr */

    waitpid(data->pid, &status, 0);

    mem_d(data);

    return status;
}
#else
    /*
     * Bidirectional piping implementation for windows using CreatePipe and DuplicateHandle +
     * other hacks.
     */
    typedef struct {
        char name_err[L_tmpnam];
        char name_out[L_tmpnam];
    } popen_t;

    FILE **task_popen(const char *command, const char *mode) {
        FILE   **handles = NULL;
        char    *cmd     = NULL;
        popen_t *open    = (popen_t*)mem_a(sizeof(popen_t) * 3);

        tmpnam(open->name_err);
        tmpnam(open->name_out);

        (void)mode; /* excluded */

        util_asprintf(&cmd, "%s -redirout=%s -redirerr=%s", command, open->name_out, open->name_err);

        system(cmd); /* HACK */
        handles    = (FILE**)(open + 1);
        handles[0] = NULL;
        handles[1] = fs_file_open(open->name_out, "r");
        handles[2] = fs_file_open(open->name_err, "r");

        return handles;
    }

    void task_pclose(FILE **files) {
        popen_t *open = ((popen_t*)files) - 1;<commit_msg>free the memory for asprintf<commit_after>/*
 * Copyright (C) 2012, 2013
 *     <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "gmqcc.h"
#include <sys/types.h>
#include <sys/stat.h>

opts_cmd_t opts;

const char *task_bins[] = {
    "./gmqcc",
    "./qcvm"
};

/*
 * TODO: Windows version
 * this implements a unique bi-directional popen-like function that
 * allows reading data from both stdout and stderr. And writing to
 * stdin :)
 *
 * Example of use:
 * FILE *handles[3] = task_popen("ls", "-l", "r");
 * if (!handles) { perror("failed to open stdin/stdout/stderr to ls");
 * // handles[0] = stdin
 * // handles[1] = stdout
 * // handles[2] = stderr
 *
 * task_pclose(handles); // to close
 */
#ifndef _WIN32
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <unistd.h>
typedef struct {
    FILE *handles[3];
    int   pipes  [3];

    int stderr_fd;
    int stdout_fd;
    int pid;
} popen_t;

FILE ** task_popen(const char *command, const char *mode) {
    int     inhandle  [2];
    int     outhandle [2];
    int     errhandle [2];
    int     trypipe;

    popen_t *data = (popen_t*)mem_a(sizeof(popen_t));

    /*
     * Parse the command now into a list for execv, this is a pain
     * in the ass.
     */
    char  *line = (char*)command;
    char **argv = NULL;
    {

        while (*line != '\0') {
            while (*line == ' ' || *line == '\t' || *line == '\n')
                *line++ = '\0';
            vec_push(argv, line);

            while (*line != '\0' && *line != ' ' &&
                   *line != '\t' && *line != '\n') line++;
        }
        vec_push(argv, '\0');
    }


    if ((trypipe = pipe(inhandle))  < 0) goto task_popen_error_0;
    if ((trypipe = pipe(outhandle)) < 0) goto task_popen_error_1;
    if ((trypipe = pipe(errhandle)) < 0) goto task_popen_error_2;

    if ((data->pid = fork()) > 0) {
        /* parent */
        close(inhandle  [0]);
        close(outhandle [1]);
        close(errhandle [1]);

        data->pipes  [0] = inhandle [1];
        data->pipes  [1] = outhandle[0];
        data->pipes  [2] = errhandle[0];
        data->handles[0] = fdopen(inhandle [1], "w");
        data->handles[1] = fdopen(outhandle[0], mode);
        data->handles[2] = fdopen(errhandle[0], mode);

        /* sigh */
        if (argv)
            vec_free(argv);
        return data->handles;
    } else if (data->pid == 0) {
        /* child */
        close(inhandle [1]);
        close(outhandle[0]);
        close(errhandle[0]);

        /* see piping documentation for this sillyness :P */
        close(0), dup(inhandle [0]);
        close(1), dup(outhandle[1]);
        close(2), dup(errhandle[1]);

        execvp(*argv, argv);
        exit(EXIT_FAILURE);
    } else {
        /* fork failed */
        goto task_popen_error_3;
    }

task_popen_error_3: close(errhandle[0]), close(errhandle[1]);
task_popen_error_2: close(outhandle[0]), close(outhandle[1]);
task_popen_error_1: close(inhandle [0]), close(inhandle [1]);
task_popen_error_0:

    if (argv)
        vec_free(argv);
    return NULL;
}

int task_pclose(FILE **handles) {
    popen_t *data   = (popen_t*)handles;
    int      status = 0;

    close(data->pipes[0]); /* stdin  */
    close(data->pipes[1]); /* stdout */
    close(data->pipes[2]); /* stderr */

    waitpid(data->pid, &status, 0);

    mem_d(data);

    return status;
}
#else
    /*
     * Bidirectional piping implementation for windows using CreatePipe and DuplicateHandle +
     * other hacks.
     */
    typedef struct {
        char name_err[L_tmpnam];
        char name_out[L_tmpnam];
    } popen_t;

    FILE **task_popen(const char *command, const char *mode) {
        FILE   **handles = NULL;
        char    *cmd     = NULL;
        popen_t *open    = (popen_t*)mem_a(sizeof(popen_t) * 3);

        tmpnam(open->name_err);
        tmpnam(open->name_out);

        (void)mode; /* excluded */

        util_asprintf(&cmd, "%s -redirout=%s -redirerr=%s", command, open->name_out, open->name_err);

        system(cmd); /* HACK */
        handles    = (FILE**)(open + 1);
        handles[0] = NULL;
        handles[1] = fs_file_open(open->name_out, "r");
        handles[2] = fs_file_open(open->name_err, "r");

        mem_d(cmd);

        return handles;
    }

    void task_pclose(FILE **files) {
        popen_t *open = ((popen_t*)files) - 1;
{'fraction_non_alphanumeric': 0.14361208974596698, 'fraction_numerical': 0.014277767476358243, 'mean_word_length': 2.5659504132231405, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 57, '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': '4746958', 'n_tokens_mistral': 3691, 'n_tokens_neox': 3558, 'n_words': 1030}