parrotcode: STDIO layer | |
Contents | C |
src/io/io_stdio.c - STDIO layer
This is the Parrot IO STDIO layer. This may provide a subset of full functionality, but must compile on any system with the ANSI C standard library. Also note that unlike the other low-level IO layers (UNIX, Win32), this is buffered IO, out of necessity.
*/
#include <stdio.h> #include "parrot/parrot.h" #include "io_private.h"
/* HEADERIZER HFILE: none */ /* HEADERIZER BEGIN: static */
PARROT_CONST_FUNCTION PARROT_CANNOT_RETURN_NULL static const char * flags_to_stdio( INTVAL flags );
static INTVAL PIO_stdio_close( SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io) ) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static ParrotIO * PIO_stdio_fdopen( PARROT_INTERP, SHIM(ParrotIOLayer *layer), PIOHANDLE fptr, INTVAL flags ) __attribute__nonnull__(1);
static INTVAL PIO_stdio_flush( SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io) ) __attribute__nonnull__(3);
static INTVAL PIO_stdio_init( PARROT_INTERP, NOTNULL(ParrotIOLayer *layer) ) __attribute__nonnull__(1) __attribute__nonnull__(2);
static INTVAL PIO_stdio_isatty( PIOHANDLE fptr ); PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static ParrotIO * PIO_stdio_open( PARROT_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(const char *spath), INTVAL flags ) __attribute__nonnull__(1) __attribute__nonnull__(3);
static size_t PIO_stdio_peek( PARROT_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), NOTNULL(STRING **buf) ) __attribute__nonnull__(1) __attribute__nonnull__(3) __attribute__nonnull__(4);
static size_t PIO_stdio_read( PARROT_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), NOTNULL(STRING **buf) ) __attribute__nonnull__(1) __attribute__nonnull__(3) __attribute__nonnull__(4);
static PIOOFF_T PIO_stdio_seek( SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), PIOOFF_T offset, INTVAL whence ) __attribute__nonnull__(3);
static PIOOFF_T PIO_stdio_tell( SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io) ) __attribute__nonnull__(3);
static size_t PIO_stdio_write( SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), NOTNULL(STRING *s) ) __attribute__nonnull__(3) __attribute__nonnull__(4);
/* HEADERIZER END: static */
extern INTVAL PIO_stdio_getblksize(PIOHANDLE fd); /* XXX Use a declaration in a header file */
/* Defined at bottom */ extern const ParrotIOLayerAPI pio_stdio_layer_api;
ParrotIOLayer pio_stdio_layer = { NULL, "stdio", PIO_L_TERMINAL, &pio_stdio_layer_api, 0, 0 };
/*
FUNCDOC: flags_to_stdio
Returns a C string representation of flags
suitable for passing to fopen()
in PIO_stdio_open()
.
*/
PARROT_CONST_FUNCTION PARROT_CANNOT_RETURN_NULL static const char * flags_to_stdio(INTVAL flags) { if ((flags & (PIO_F_WRITE | PIO_F_READ | PIO_F_APPEND)) == (PIO_F_WRITE | PIO_F_READ | PIO_F_APPEND)) { return "a+b"; } else if ((flags & (PIO_F_WRITE | PIO_F_READ | PIO_F_TRUNC)) == (PIO_F_WRITE | PIO_F_READ | PIO_F_TRUNC)) { return "w+b"; } else if ((flags & (PIO_F_WRITE | PIO_F_READ)) == (PIO_F_WRITE | PIO_F_READ)) { return "r+b"; } else if (flags & PIO_F_APPEND) { return "ab"; } else if (flags & PIO_F_WRITE) { return "wb"; } else { /* PIO_F_READ, hopefully */ return "rb"; } }
/*
FUNCDOC: PIO_stdio_init
Setup standard streams, etc.
*/
static INTVAL PIO_stdio_init(PARROT_INTERP, NOTNULL(ParrotIOLayer *layer)) { #ifdef PIO_OS_STDIO /* Only set standard handles if stdio is the OS IO */ PIO_STDIN(interp) = new_io_pmc(interp, PIO_stdio_fdopen(interp, layer, stdin, PIO_F_READ));
PIO_STDOUT(interp)
= new_io_pmc(interp,
PIO_stdio_fdopen(interp, layer, stdout, PIO_F_WRITE));
PIO_STDERR(interp)
= new_io_pmc(interp,
PIO_stdio_fdopen(interp, layer, stderr, PIO_F_WRITE));
#else /* PIO_OS_STDIO */
UNUSED(interp);
UNUSED(layer);
#endif /* PIO_OS_STDIO */
return 0;
}
/*
FUNCDOC: PIO_stdio_open
Open modes (read, write, append, etc.) are done in pseudo-Perl style using <
, >
, etc.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static ParrotIO * PIO_stdio_open(PARROT_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(const char *spath), INTVAL flags) { ParrotIO *io; const char *oflags; INTVAL type; FILE *fptr; type = PIO_TYPE_FILE;
if ((flags & (PIO_F_WRITE | PIO_F_READ)) == 0)
return NULL;
oflags = flags_to_stdio(flags);
/* Only files for now */
flags |= PIO_F_FILE;
/* Try opening the file- note that this can't really handle O_EXCL, etc. */
fptr = fopen(spath, oflags);
if (fptr == NULL && errno == ENOENT && (flags & PIO_F_WRITE)) {
fptr = fopen(spath, "w+b");
}
/* File open */
if (fptr != NULL) {
if (PIO_stdio_isatty((PIOHANDLE)fptr))
flags |= PIO_F_CONSOLE;
io = PIO_new(interp, type, flags, 0);
io->fd = (PIOHANDLE)fptr;
return io;
}
return NULL;
}
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static ParrotIO * PIO_stdio_fdopen(PARROT_INTERP, SHIM(ParrotIOLayer *layer), PIOHANDLE fptr, INTVAL flags) { ParrotIO *io; const INTVAL mode = 0;
if (PIO_stdio_isatty(fptr))
flags |= PIO_F_CONSOLE;
/* fdopened files are always shared */
flags |= PIO_F_SHARED;
io = PIO_new(interp, PIO_F_FILE, flags, mode);
io->fd = fptr;
return io;
}
static INTVAL PIO_stdio_close(SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io)) { FILE * const fptr = (FILE*)io->fd;
if (fptr != NULL)
fclose(fptr);
io->fd = (PIOHANDLE)NULL;
return 0;
}
static INTVAL PIO_stdio_isatty(PIOHANDLE fptr) { UNUSED(fptr);
/* no obvious way to check for this with STDIO */
return 0;
}
static size_t PIO_stdio_peek(PARROT_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), NOTNULL(STRING **buf)) { FILE * const fptr = (FILE *)io->fd; STRING * const s = PIO_make_io_string(interp, buf, 1);
/* read the next byte into the buffer */
const size_t bytes = fread(s->strstart, 1, 1, fptr);
/* if we got anything from the stream, push it back on */
if (bytes) {
s->bufused = s->strlen = 1;
ungetc(*(char*)s->strstart, fptr);
}
else
s->bufused = s->strlen = 1;
return bytes;
}
INTVAL PIO_stdio_getblksize(PIOHANDLE fptr) { UNUSED(fptr);
/* Hard coded for now */
return PIO_BLKSIZE;
}
static INTVAL PIO_stdio_flush(SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io)) { return fflush((FILE*)io->fd); }
static size_t PIO_stdio_read(PARROT_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), NOTNULL(STRING **buf)) { FILE * const fptr = (FILE *)io->fd; STRING * const s = PIO_make_io_string(interp, buf, 2048); const size_t len = s->bufused; void * const buffer = s->strstart;
const size_t bytes = fread(buffer, 1, len, fptr);
s->bufused = s->strlen = bytes;
if (bytes != len) {
if (feof(fptr)) {
io->flags |= PIO_F_EOF;
}
}
return bytes;
}
static size_t PIO_stdio_write(SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), NOTNULL(STRING *s)) { void * const buffer = s->strstart; return fwrite(buffer, 1, s->bufused, (FILE*)io->fd); }
static PIOOFF_T PIO_stdio_seek(SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io), PIOOFF_T offset, INTVAL whence) { PIOOFF_T pos; errno = 0;
if ((pos = fseek((FILE*)io->fd, (long)offset, whence)) >= 0) {
io->lpos = io->fpos;
io->fpos = pos;
}
/* Seek clears EOF */
io->flags &= ~PIO_F_EOF;
return pos;
}
static PIOOFF_T PIO_stdio_tell(SHIM_INTERP, SHIM(ParrotIOLayer *layer), NOTNULL(ParrotIO *io)) { return (ftell((FILE*)io->fd)); }
const ParrotIOLayerAPI pio_stdio_layer_api = { PIO_stdio_init, PIO_base_new_layer, PIO_base_delete_layer, PIO_null_push_layer, PIO_null_pop_layer, PIO_stdio_open, PIO_null_open2, PIO_null_open3, PIO_null_open_async, PIO_stdio_fdopen, PIO_stdio_close, PIO_stdio_write, PIO_null_write_async, PIO_stdio_read, PIO_null_read_async, PIO_stdio_flush, PIO_stdio_peek, PIO_stdio_seek, PIO_stdio_tell, PIO_null_setbuf, PIO_null_setlinebuf, PIO_null_getcount, PIO_null_fill, PIO_null_eof, NULL, /* no poll */ NULL, /* no socket */ NULL, /* no connect */ NULL, /* no send */ NULL, /* no recv */ NULL, /* no bind */ NULL, /* no listen */ NULL /* no accept */ };
/*
src/io/io_buf.c, src/io/io_passdown.c, src/io/io_unix.c, src/io/io_win32.c, src/io/io.c, src/io/io_private.h.
Adapted from io_unix.c by Josh Wilmes (josh@hitchhiker.org).
*/
/* * Local variables: * c-file-style: "parrot" * End: * vim: expandtab shiftwidth=4: */
|