<commit_before>/* io_win32.c
 *  Copyright: 2001-2003 The Perl Foundation.  All Rights Reserved.
 *  CVS Info
 *      $Id$
 *  Overview:
 *      This is the Parrot IO OS layer for Win32 platforms.
 *  Data Structure and Algorithms:
 *  History:
 *      Initially written by <NAME>
 *  Notes:
 *  References:
 *      Win32 System Programming, 2nd Edition
 */

#ifdef WIN32
#  include <windows.h>
#endif

#include "parrot/parrot.h"
#include "io_private.h"

#ifdef PIO_OS_WIN32

#  include <tchar.h>

/* Defined at bottom */
extern ParrotIOLayerAPI pio_win32_layer_api;

ParrotIOLayer pio_win32_layer = {
    NULL,
    "win32",
    PIO_L_TERMINAL,
    &pio_win32_layer_api,
    0, 0
};


/*
 * Currently keeping layer prototypes local to each layer
 * file.
 */

static INTVAL    PIO_win32_init(theINTERP, ParrotIOLayer *layer);
static ParrotIO *PIO_win32_open(theINTERP, ParrotIOLayer *layer,
                                const char *spath, INTVAL flags);
static ParrotIO *PIO_win32_fdopen(theINTERP, ParrotIOLayer *layer,
                                  PIOHANDLE fd, INTVAL flags);
static INTVAL PIO_win32_close(theINTERP, ParrotIOLayer *layer, ParrotIO *io);
static INTVAL PIO_win32_flush(theINTERP, ParrotIOLayer *layer, ParrotIO *io);
static size_t    PIO_win32_read(theINTERP, ParrotIOLayer *layer,
                                ParrotIO *io, void *buffer, size_t len);
static size_t    PIO_win32_write(theINTERP, ParrotIOLayer *layer,
                                 ParrotIO *io, const void *buffer, size_t len);
static INTVAL    PIO_win32_puts(theINTERP, ParrotIOLayer *l, ParrotIO *io,
                                const char *s);
static PIOOFF_T  PIO_win32_seek(theINTERP, ParrotIOLayer *l, ParrotIO *io,
                                PIOOFF_T off, INTVAL whence);
static PIOOFF_T  PIO_win32_tell(theINTERP, ParrotIOLayer *l, ParrotIO *io);
static INTVAL    PIO_win32_isatty(PIOHANDLE fd);


/* Convert to platform specific bit open flags */
static INTVAL
flags_to_win32(INTVAL flags, DWORD * fdwAccess,
               DWORD * fdwShareMode, DWORD * fdwCreate)
{
    if ((flags & (PIO_F_WRITE | PIO_F_READ)) == (PIO_F_WRITE | PIO_F_READ)) {
        *fdwAccess = GENERIC_WRITE | GENERIC_READ;
        if (flags & PIO_F_TRUNC)
            *fdwCreate = CREATE_ALWAYS;
        else
            *fdwCreate = OPEN_ALWAYS;
    }
    else if (flags & PIO_F_WRITE) {
        *fdwAccess = GENERIC_WRITE;
        if (flags & PIO_F_TRUNC)
            *fdwCreate = CREATE_ALWAYS;
        else
            *fdwCreate = OPEN_ALWAYS;
    }
    else if (flags & PIO_F_READ) {
        *fdwAccess = GENERIC_READ;
        *fdwCreate = OPEN_EXISTING;
    }

    *fdwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
    if (flags & PIO_F_APPEND) {
        /* dealt with specially in _write and _puts */
    }
    return 1;
}


/*
 * Setup standard streams.
 */
static INTVAL
PIO_win32_init(theINTERP, ParrotIOLayer *layer)
{
    HANDLE h;
    if ((h = GetStdHandle(STD_INPUT_HANDLE)) != INVALID_HANDLE_VALUE) {
        PIO_STDIN(interpreter) = new_io_pmc(interpreter, 
            PIO_win32_fdopen(interpreter, layer, h, PIO_F_READ));
    }
    else {
        return -1;
    }
    if ((h = GetStdHandle(STD_OUTPUT_HANDLE))
        != INVALID_HANDLE_VALUE) {
        PIO_STDOUT(interpreter) = new_io_pmc(interpreter,
            PIO_win32_fdopen(interpreter, layer, h, PIO_F_WRITE));
    }
    else {
        return -2;
    }
    if ((h = GetStdHandle(STD_ERROR_HANDLE)) != INVALID_HANDLE_VALUE) {
        PIO_STDERR(interpreter) = new_io_pmc(interpreter,
            PIO_win32_fdopen(interpreter, layer, h, PIO_F_WRITE));
    }
    else {
        return -3;
    }
    return 0;
}


INTVAL
PIO_win32_getblksize(PIOHANDLE fd)
{
    /* Hard coded for now */
    return PIO_BLKSIZE;
}


static ParrotIO *
PIO_win32_open(theINTERP, ParrotIOLayer *layer,
               const char *spath, INTVAL flags)
{
    ParrotIO *io;
    int type;
    DWORD fAcc, fShare, fCreat;
    PIOHANDLE fd;
    type = PIO_TYPE_FILE;
#  if 0
    if ((Interp_flags_TEST(interpreter, PARROT_DEBUG_FLAG)) != 0) {
        fprintf(stderr, "PIO_win32_open: %s\n", spath);
    }
#  endif
    if ((flags & (PIO_F_WRITE | PIO_F_READ)) == 0)
        return (ParrotIO *)NULL;

    /* Set open flags - <, >, >>, +<, +> */
    /* add ? and ! for block/non-block */
    if (flags_to_win32(flags, &fAcc, &fShare, &fCreat) < 0)
        return (ParrotIO *)NULL;

    /* Only files for now */
    flags |= PIO_F_FILE;

    fd = CreateFile(spath, fAcc, 0, NULL, fCreat, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fd != INVALID_HANDLE_VALUE) {
        io = PIO_new(interpreter, type, flags, 0);
        io->fd = fd;
        return io;
    }
    else {
        int err = GetLastError();
        if(err) {}
    }

    return (ParrotIO *)NULL;
}


static ParrotIO *
PIO_win32_fdopen(theINTERP, ParrotIOLayer *layer, PIOHANDLE fd, INTVAL flags)
{
    ParrotIO *io;
    INTVAL mode;
    mode = 0;

    if (PIO_win32_isatty(fd))
        flags |= PIO_F_CONSOLE;

    /* fdopened files are always shared */
    flags |= PIO_F_SHARED;

    io = PIO_new(interpreter, PIO_F_FILE, flags, mode);
    io->fd = fd;
    return io;
}


static INTVAL
PIO_win32_close(theINTERP, ParrotIOLayer *layer, ParrotIO *io)
{
    if (io && io->fd != INVALID_HANDLE_VALUE) {
        CloseHandle(io->fd);
        io->fd = INVALID_HANDLE_VALUE;
    }
    return 0;
}


INTVAL
PIO_win32_isatty(PIOHANDLE fd)
{
    DWORD ftype = GetFileType(fd);
    if (ftype == FILE_TYPE_CHAR)
        return 1;
    return 0;
}


static INTVAL
PIO_win32_flush(theINTERP, ParrotIOLayer *layer, ParrotIO *io)
{
    /*
     * FlushFileBuffers won't work for console handles. From the MS help file:
     *
     * Windows NT: The function fails if hFile is a handle to console output. That is because console output is not buffered.
     * The function returns FALSE, and GetLastError returns ERROR_INVALID_HANDLE.
     * 
     * Windows 9x: The function does nothing if hFile is a handle to console output. That is because console output is not buffered.
     * The function returns TRUE, but it does nothing.
     */
    return FlushFileBuffers(io->fd);
}


static size_t
PIO_win32_read(theINTERP, ParrotIOLayer *layer, ParrotIO *io,
               void *buffer, size_t len)
{
    DWORD countread;
    if (ReadFile(io->fd, (LPVOID) buffer, (DWORD) len, &countread, NULL))
        if (countread > 0)
            return (size_t)countread;
        else
            /* EOF if read 0 and bytes were requested */
            io->flags |= PIO_F_EOF;
    else if (GetLastError() != NO_ERROR)
            /* FIXME : An error occured */
        ;
    return 0;
}


static size_t
PIO_win32_write(theINTERP, ParrotIOLayer *layer, ParrotIO *io,
                const void *buffer, size_t len)
{
    DWORD countwrote = 0;
    /* do it by hand, Win32 hasn't any specific flag */
    if (io->flags & PIO_F_APPEND)
    {
        LARGE_INTEGER p;
        p.LowPart = 0;
        p.HighPart = 0;

        p.LowPart = SetFilePointer(io->fd, p.LowPart,
                                   &p.HighPart, FILE_END);
        if (p.LowPart == 0xFFFFFFFF && (GetLastError() != NO_ERROR)) {
            /* Error - exception */
            return -1;
        }
    }

    if (io
        && WriteFile(io->fd, (LPCSTR) buffer, (DWORD) len, &countwrote, NULL))<commit_msg>Only set PIO_F_EOF in PIO_win32_read if bytes are requested<commit_after>/* io_win32.c
 *  Copyright: 2001-2003 The Perl Foundation.  All Rights Reserved.
 *  CVS Info
 *      $Id$
 *  Overview:
 *      This is the Parrot IO OS layer for Win32 platforms.
 *  Data Structure and Algorithms:
 *  History:
 *      Initially written by <NAME>
 *  Notes:
 *  References:
 *      Win32 System Programming, 2nd Edition
 */

#ifdef WIN32
#  include <windows.h>
#endif

#include "parrot/parrot.h"
#include "io_private.h"

#ifdef PIO_OS_WIN32

#  include <tchar.h>

/* Defined at bottom */
extern ParrotIOLayerAPI pio_win32_layer_api;

ParrotIOLayer pio_win32_layer = {
    NULL,
    "win32",
    PIO_L_TERMINAL,
    &pio_win32_layer_api,
    0, 0
};


/*
 * Currently keeping layer prototypes local to each layer
 * file.
 */

static INTVAL    PIO_win32_init(theINTERP, ParrotIOLayer *layer);
static ParrotIO *PIO_win32_open(theINTERP, ParrotIOLayer *layer,
                                const char *spath, INTVAL flags);
static ParrotIO *PIO_win32_fdopen(theINTERP, ParrotIOLayer *layer,
                                  PIOHANDLE fd, INTVAL flags);
static INTVAL PIO_win32_close(theINTERP, ParrotIOLayer *layer, ParrotIO *io);
static INTVAL PIO_win32_flush(theINTERP, ParrotIOLayer *layer, ParrotIO *io);
static size_t    PIO_win32_read(theINTERP, ParrotIOLayer *layer,
                                ParrotIO *io, void *buffer, size_t len);
static size_t    PIO_win32_write(theINTERP, ParrotIOLayer *layer,
                                 ParrotIO *io, const void *buffer, size_t len);
static INTVAL    PIO_win32_puts(theINTERP, ParrotIOLayer *l, ParrotIO *io,
                                const char *s);
static PIOOFF_T  PIO_win32_seek(theINTERP, ParrotIOLayer *l, ParrotIO *io,
                                PIOOFF_T off, INTVAL whence);
static PIOOFF_T  PIO_win32_tell(theINTERP, ParrotIOLayer *l, ParrotIO *io);
static INTVAL    PIO_win32_isatty(PIOHANDLE fd);


/* Convert to platform specific bit open flags */
static INTVAL
flags_to_win32(INTVAL flags, DWORD * fdwAccess,
               DWORD * fdwShareMode, DWORD * fdwCreate)
{
    if ((flags & (PIO_F_WRITE | PIO_F_READ)) == (PIO_F_WRITE | PIO_F_READ)) {
        *fdwAccess = GENERIC_WRITE | GENERIC_READ;
        if (flags & PIO_F_TRUNC)
            *fdwCreate = CREATE_ALWAYS;
        else
            *fdwCreate = OPEN_ALWAYS;
    }
    else if (flags & PIO_F_WRITE) {
        *fdwAccess = GENERIC_WRITE;
        if (flags & PIO_F_TRUNC)
            *fdwCreate = CREATE_ALWAYS;
        else
            *fdwCreate = OPEN_ALWAYS;
    }
    else if (flags & PIO_F_READ) {
        *fdwAccess = GENERIC_READ;
        *fdwCreate = OPEN_EXISTING;
    }

    *fdwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
    if (flags & PIO_F_APPEND) {
        /* dealt with specially in _write and _puts */
    }
    return 1;
}


/*
 * Setup standard streams.
 */
static INTVAL
PIO_win32_init(theINTERP, ParrotIOLayer *layer)
{
    HANDLE h;
    if ((h = GetStdHandle(STD_INPUT_HANDLE)) != INVALID_HANDLE_VALUE) {
        PIO_STDIN(interpreter) = new_io_pmc(interpreter, 
            PIO_win32_fdopen(interpreter, layer, h, PIO_F_READ));
    }
    else {
        return -1;
    }
    if ((h = GetStdHandle(STD_OUTPUT_HANDLE))
        != INVALID_HANDLE_VALUE) {
        PIO_STDOUT(interpreter) = new_io_pmc(interpreter,
            PIO_win32_fdopen(interpreter, layer, h, PIO_F_WRITE));
    }
    else {
        return -2;
    }
    if ((h = GetStdHandle(STD_ERROR_HANDLE)) != INVALID_HANDLE_VALUE) {
        PIO_STDERR(interpreter) = new_io_pmc(interpreter,
            PIO_win32_fdopen(interpreter, layer, h, PIO_F_WRITE));
    }
    else {
        return -3;
    }
    return 0;
}


INTVAL
PIO_win32_getblksize(PIOHANDLE fd)
{
    /* Hard coded for now */
    return PIO_BLKSIZE;
}


static ParrotIO *
PIO_win32_open(theINTERP, ParrotIOLayer *layer,
               const char *spath, INTVAL flags)
{
    ParrotIO *io;
    int type;
    DWORD fAcc, fShare, fCreat;
    PIOHANDLE fd;
    type = PIO_TYPE_FILE;
#  if 0
    if ((Interp_flags_TEST(interpreter, PARROT_DEBUG_FLAG)) != 0) {
        fprintf(stderr, "PIO_win32_open: %s\n", spath);
    }
#  endif
    if ((flags & (PIO_F_WRITE | PIO_F_READ)) == 0)
        return (ParrotIO *)NULL;

    /* Set open flags - <, >, >>, +<, +> */
    /* add ? and ! for block/non-block */
    if (flags_to_win32(flags, &fAcc, &fShare, &fCreat) < 0)
        return (ParrotIO *)NULL;

    /* Only files for now */
    flags |= PIO_F_FILE;

    fd = CreateFile(spath, fAcc, fShare, NULL, fCreat, FILE_ATTRIBUTE_NORMAL, NULL);
    if (fd != INVALID_HANDLE_VALUE) {
        io = PIO_new(interpreter, type, flags, 0);
        io->fd = fd;
        return io;
    }
    else {
        int err = GetLastError();
        if(err) {}
    }

    return (ParrotIO *)NULL;
}


static ParrotIO *
PIO_win32_fdopen(theINTERP, ParrotIOLayer *layer, PIOHANDLE fd, INTVAL flags)
{
    ParrotIO *io;
    INTVAL mode;
    mode = 0;

    if (PIO_win32_isatty(fd))
        flags |= PIO_F_CONSOLE;

    /* fdopened files are always shared */
    flags |= PIO_F_SHARED;

    io = PIO_new(interpreter, PIO_F_FILE, flags, mode);
    io->fd = fd;
    return io;
}


static INTVAL
PIO_win32_close(theINTERP, ParrotIOLayer *layer, ParrotIO *io)
{
    if (io && io->fd != INVALID_HANDLE_VALUE) {
        CloseHandle(io->fd);
        io->fd = INVALID_HANDLE_VALUE;
    }
    return 0;
}


INTVAL
PIO_win32_isatty(PIOHANDLE fd)
{
    DWORD ftype = GetFileType(fd);
    if (ftype == FILE_TYPE_CHAR)
        return 1;
    return 0;
}


static INTVAL
PIO_win32_flush(theINTERP, ParrotIOLayer *layer, ParrotIO *io)
{
    /*
     * FlushFileBuffers won't work for console handles. From the MS help file:
     *
     * Windows NT: The function fails if hFile is a handle to console output. That is because console output is not buffered.
     * The function returns FALSE, and GetLastError returns ERROR_INVALID_HANDLE.
     * 
     * Windows 9x: The function does nothing if hFile is a handle to console output. That is because console output is not buffered.
     * The function returns TRUE, but it does nothing.
     */
    return FlushFileBuffers(io->fd);
}


static size_t
PIO_win32_read(theINTERP, ParrotIOLayer *layer, ParrotIO *io,
               void *buffer, size_t len)
{
    DWORD countread;
    if (ReadFile(io->fd, (LPVOID) buffer, (DWORD) len, &countread, NULL)) {
        if (countread > 0)
            return (size_t)countread;
        else if (len > 0)
            /* EOF if read 0 and bytes were requested */
            io->flags |= PIO_F_EOF;
    }
    else {
        /* FIXME : An error occured */
    }
    
    return 0;
}


static size_t
PIO_win32_write(theINTERP, ParrotIOLayer *layer, ParrotIO *io,
                const void *buffer, size_t len)
{
    DWORD countwrote = 0;
    /* do it by hand, Win32 hasn't any specific flag */
    if (io->flags & PIO_F_APPEND)
    {
        LARGE_INTEGER p;
        p.LowPart = 0;
        p.HighPart = 0;

        p.LowPart = SetFilePointer(io->fd, p.LowPart,
                                   &p.HighPart, FILE_END);
        if (p.LowPart == 0xFFFFFFFF && (GetLastError() != NO_ERROR)) {
            /* Error - exception */
            return -1;
        }
    }

    if (io
        && WriteFile(io->fd, (LPCSTR) buffer, (DWORD) len, &countwrote, NULL))
{'fraction_non_alphanumeric': 0.10227195659545608, 'fraction_numerical': 0.014920311970159377, 'mean_word_length': 2.481936245572609, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2521784', 'n_tokens_mistral': 5484, 'n_tokens_neox': 5272, 'n_words': 1283}