<commit_before>/*
* Copyright (c) 2019 <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.
*/

/* Compiler feature test macros for things */
#define _DEFAULT_SOURCE
#define _BSD_SOURCE

#include <stdio.h>
#include <janet/janet.h>
#include <errno.h>
#include "util.h"

#define IO_WRITE 1
#define IO_READ 2
#define IO_APPEND 4
#define IO_UPDATE 8
#define IO_NOT_CLOSEABLE 16
#define IO_CLOSED 32
#define IO_BINARY 64
#define IO_SERIALIZABLE 128
#define IO_PIPED 256

typedef struct IOFile IOFile;
struct IOFile {
    FILE *file;
    int flags;
};

static int janet_io_gc(void *p, size_t len);

JanetAbstractType janet_io_filetype = {
    "core/file",
    janet_io_gc,
    NULL
};

/* Check arguments to fopen */
static int checkflags(const uint8_t *str) {
    int flags = 0;
    int32_t i;
    int32_t len = janet_string_length(str);
    if (!len || len > 3)
        janet_panic("file mode must have a length between 1 and 3");
    switch (*str) {
        default:
            janet_panicf("invalid flag %c, expected w, a, or r", *str);
            break;
        case 'w':
            flags |= IO_WRITE;
            break;
        case 'a':
            flags |= IO_APPEND;
            break;
        case 'r':
            flags |= IO_READ;
            break;
    }
    for (i = 1; i < len; i++) {
        switch (str[i]) {
            default:
                janet_panicf("invalid flag %c, expected + or b", str[i]);
                break;
            case '+':
                if (flags & IO_UPDATE) return -1;
                flags |= IO_UPDATE;
                break;
            case 'b':
                if (flags & IO_BINARY) return -1;
                flags |= IO_BINARY;
                break;
        }
    }
    return flags;
}

static Janet makef(FILE *f, int flags) {
    IOFile *iof = (IOFile *) janet_abstract(&janet_io_filetype, sizeof(IOFile));
    iof->file = f;
    iof->flags = flags;
    return janet_wrap_abstract(iof);
}

/* Open a process */
#ifdef __EMSCRIPTEN__
static Janet janet_io_popen(int32_t argc, Janet *argv) {
    (void) argc;
    (void) argv;
    janet_panic("not implemented on this platform");
    return janet_wrap_nil();
}
#else
static Janet janet_io_popen(int32_t argc, Janet *argv) {
    janet_arity(argc, 1, 2);
    const uint8_t *fname = janet_getstring(argv, 0);
    const uint8_t *fmode = NULL;
    if (argc == 2) {
        fmode = janet_getkeyword(argv, 1);
        if (janet_string_length(fmode) != 1 ||
            !(fmode[0] == 'r' || fmode[0] == 'w')) {
            janet_panicf("invalid file mode :%S, expected :r or :w", fmode);
        }
    }
    int flags = (fmode && fmode[0] == '2')
        ? IO_PIPED | IO_WRITE
        : IO_PIPED | IO_READ;
#ifdef JANET_WINDOWS
#define popen _popen
#endif
    FILE *f = popen((const char *)fname, (const char *)fmode);
    if (!f) {
        return janet_wrap_nil();
    }
    return makef(f, flags);
}
#endif

static Janet janet_io_fopen(int32_t argc, Janet *argv) {
    janet_arity(argc, 1, 2);
    const uint8_t *fname = janet_getstring(argv, 0);
    const uint8_t *fmode;
    int flags;
    if (argc == 2) {
        fmode = janet_getkeyword(argv, 1);
        flags = checkflags(fmode);
    } else {
        fmode = (const uint8_t *)"r";
        flags = IO_READ;
    }
    FILE *f = fopen((const char *)fname, (const char *)fmode);
    return f ? makef(f, flags) : janet_wrap_nil();
}

/* Read up to n bytes into buffer. Return error string if error. */<commit_msg>Fix popen bug.<commit_after>/*
* Copyright (c) 2019 <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.
*/

/* Compiler feature test macros for things */
#define _DEFAULT_SOURCE
#define _BSD_SOURCE

#include <stdio.h>
#include <janet/janet.h>
#include <errno.h>
#include "util.h"

#define IO_WRITE 1
#define IO_READ 2
#define IO_APPEND 4
#define IO_UPDATE 8
#define IO_NOT_CLOSEABLE 16
#define IO_CLOSED 32
#define IO_BINARY 64
#define IO_SERIALIZABLE 128
#define IO_PIPED 256

typedef struct IOFile IOFile;
struct IOFile {
    FILE *file;
    int flags;
};

static int janet_io_gc(void *p, size_t len);

JanetAbstractType janet_io_filetype = {
    "core/file",
    janet_io_gc,
    NULL
};

/* Check arguments to fopen */
static int checkflags(const uint8_t *str) {
    int flags = 0;
    int32_t i;
    int32_t len = janet_string_length(str);
    if (!len || len > 3)
        janet_panic("file mode must have a length between 1 and 3");
    switch (*str) {
        default:
            janet_panicf("invalid flag %c, expected w, a, or r", *str);
            break;
        case 'w':
            flags |= IO_WRITE;
            break;
        case 'a':
            flags |= IO_APPEND;
            break;
        case 'r':
            flags |= IO_READ;
            break;
    }
    for (i = 1; i < len; i++) {
        switch (str[i]) {
            default:
                janet_panicf("invalid flag %c, expected + or b", str[i]);
                break;
            case '+':
                if (flags & IO_UPDATE) return -1;
                flags |= IO_UPDATE;
                break;
            case 'b':
                if (flags & IO_BINARY) return -1;
                flags |= IO_BINARY;
                break;
        }
    }
    return flags;
}

static Janet makef(FILE *f, int flags) {
    IOFile *iof = (IOFile *) janet_abstract(&janet_io_filetype, sizeof(IOFile));
    iof->file = f;
    iof->flags = flags;
    return janet_wrap_abstract(iof);
}

/* Open a process */
#ifdef __EMSCRIPTEN__
static Janet janet_io_popen(int32_t argc, Janet *argv) {
    (void) argc;
    (void) argv;
    janet_panic("not implemented on this platform");
    return janet_wrap_nil();
}
#else
static Janet janet_io_popen(int32_t argc, Janet *argv) {
    janet_arity(argc, 1, 2);
    const uint8_t *fname = janet_getstring(argv, 0);
    const uint8_t *fmode = NULL;
    int flags;
    if (argc == 2) {
        fmode = janet_getkeyword(argv, 1);
        if (janet_string_length(fmode) != 1 ||
            !(fmode[0] == 'r' || fmode[0] == 'w')) {
            janet_panicf("invalid file mode :%S, expected :r or :w", fmode);
        }
        flags = IO_PIPED | (fmode[0] == 'r' ? IO_READ : IO_WRITE);
    } else {
        fmode = (const uint8_t *)"r";
        flags = IO_PIPED | IO_READ;
    }
#ifdef JANET_WINDOWS
#define popen _popen
#endif
    FILE *f = popen((const char *)fname, (const char *)fmode);
    if (!f) {
        return janet_wrap_nil();
    }
    return makef(f, flags);
}
#endif

static Janet janet_io_fopen(int32_t argc, Janet *argv) {
    janet_arity(argc, 1, 2);
    const uint8_t *fname = janet_getstring(argv, 0);
    const uint8_t *fmode;
    int flags;
    if (argc == 2) {
        fmode = janet_getkeyword(argv, 1);
        flags = checkflags(fmode);
    } else {
        fmode = (const uint8_t *)"r";
        flags = IO_READ;
    }
    FILE *f = fopen((const char *)fname, (const char *)fmode);
    return f ? makef(f, flags) : janet_wrap_nil();
}

/* Read up to n bytes into buffer. Return error string if error. */
{'fraction_non_alphanumeric': 0.10709133281544779, 'fraction_numerical': 0.012873155032737765, 'mean_word_length': 2.642683912691997, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, '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': '5165208', 'n_tokens_mistral': 3055, 'n_tokens_neox': 2906, 'n_words': 1009}