Oops. The patch helps. -Melvin
diff -urN tmp/parrot/MANIFEST parrot/MANIFEST --- tmp/parrot/MANIFEST Tue Jan 1 11:58:13 2002 +++ parrot/MANIFEST Tue Jan 1 16:40:01 2002 @@ -79,6 +79,8 @@ include/parrot/trace.h include/parrot/unicode.h interpreter.c +io/io.c +io/io_os.c jit/i386/core.jit jit/i386/lib.jit jit/i386/string.jit diff -urN tmp/parrot/Makefile.in parrot/Makefile.in --- tmp/parrot/Makefile.in Tue Jan 1 15:11:57 2002 +++ parrot/Makefile.in Tue Jan 1 15:19:24 2002 @@ -73,12 +73,14 @@ CHARTYPE_O_FILES = chartypes/unicode$(O) chartypes/usascii$(O) +IO_O_FILES = io/io$(O) io/io_os$(O) + INTERP_O_FILES = global_setup$(O) interpreter$(O) parrot$(O) register$(O) \ core_ops$(O) core_ops_prederef$(O) memory$(O) packfile$(O) stacks$(O) \ string$(O) encoding$(O) chartype$(O) runops_cores$(O) trace$(O) pmc$(O) key$(O) \ platform$(O) ${jit_o} resources$(O) -O_FILES = $(INTERP_O_FILES) $(CLASS_O_FILES) $(ENCODING_O_FILES) $(CHARTYPE_O_FILES) +O_FILES = $(INTERP_O_FILES) $(IO_O_FILES) $(CLASS_O_FILES) $(ENCODING_O_FILES) +$(CHARTYPE_O_FILES) ############################################################################### diff -urN tmp/parrot/core.ops parrot/core.ops --- tmp/parrot/core.ops Tue Jan 1 12:22:54 2002 +++ parrot/core.ops Tue Jan 1 16:22:35 2002 @@ -73,12 +73,21 @@ ######################################## +=item B<close>(p) + +Close IO stream $1. + =item B<close>(i|ic) Close file opened on file descriptor $1. =cut +inline op close(p) { + PIO_close(interpreter, (ParrotIO*)($1->data)); + goto NEXT(); +} + inline op close(i|ic) { fclose((FILE *)$1); goto NEXT(); @@ -111,6 +120,10 @@ ######################################## +=item B<open>(p, s|sc, s|sc) + +Open file named $2 with Perl style mode string specified in $3, and +create the IO stream PMC into $1. =item B<open>(i, s|sc) @@ -124,6 +137,18 @@ =cut +inline op open(p, s|sc, s|sc) { + ParrotIO * io; + STRING *path = $2; + STRING *mode = $3; + io = PIO_open(interpreter, path->bufstart, mode->bufstart); + if(!io) { + /* FIXME: Handle error */ + } + $1 = new_io_pmc(interpreter, io); + goto NEXT(); +} + inline op open(i, s|sc) { if (! ($1 = (INTVAL)fopen(($2)->bufstart, "r+"))) { perror("Can't open"); @@ -222,6 +247,8 @@ =item B<print>(i|ic, p) +=item B<print>(p, s|sc) + Print $2 to the file on $1. (0, 1, and 2 correspond to stdin, stdout, and stderr) @@ -247,6 +274,16 @@ goto NEXT(); } +op print(p, s|sc) { + ParrotIO * io; + STRING *s = $2; + io = (ParrotIO*)($1->data); + if (s && string_length(s) && io) { + PIO_puts(interpreter, io, (const char *)s->bufstart); + } + goto NEXT(); +} + op print(p) { PMC *p = $1; STRING *s = (p->vtable->get_string(interpreter, p)); @@ -325,6 +362,21 @@ } goto NEXT(); } + + +######################################## + +=item B<puts>(s|sc) + +Print $1 to standard output stream + +op puts(s|sc) { + STRING *s = $1; + if (s && string_length(s)) { + PIO_puts(interpreter, pio_stdout, (const char *) s->bufstart); + } + goto NEXT(); +} ######################################## diff -urN tmp/parrot/include/parrot/io.h parrot/include/parrot/io.h --- tmp/parrot/include/parrot/io.h Mon Sep 17 21:16:59 2001 +++ parrot/include/parrot/io.h Tue Jan 1 16:38:23 2002 @@ -3,17 +3,221 @@ * CVS Info * $Id: io.h,v 1.1 2001/09/18 01:16:59 gregor Exp $ * Overview: - * IO operations header + * Parrot IO subsystem * Data Structure and Algorithms: * History: + * Originally written by Melvin Smith * Notes: * References: + * Some ideas and goals from Perl5.7 and Nick Ing-Simmons' work */ #if !defined(PARROT_IO_H_GUARD) #define PARROT_IO_H_GUARD -#define Init_IO(x) +#include "parrot/parrot.h" + +#ifndef SSIZE_MAX +#define SSIZE_MAX 8192 +#endif + +#ifndef STDIN_FILENO +# define STDIN_FILENO 0 +#endif + +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +#endif + +#ifndef STDERR_FILENO +# define STDERR_FILENO 2 +#endif + + +/* Average block size of most systems (usually varies from 2k-8k), + * later we can add some config to query it from the system at + * build time (struct stat.st_blksize maybe). + */ +#define PIO_BLKSIZE 4096 +#define PIO_LINEBUFSIZE 256 + + +enum { + PIO_TYPE_FILE, + PIO_TYPE_PIPE, + PIO_TYPE_SOCKET, + PIO_TYPE_MAX +}; + +enum { + PIO_BUFTYPE_NONE = 0, + PIO_BUFTYPE_FULL, + PIO_BUFTYPE_LINE, + PIO_BUFTYPE_MAX +}; + + +typedef struct _ParrotIOLayerAPI ParrotIOLayerAPI; +typedef struct _ParrotIOLayer ParrotIOLayer; +typedef struct _ParrotIOFilter ParrotIOFilter; +typedef struct _ParrotIOBuf ParrotIOBuf; +typedef struct _ParrotIO ParrotIO; + +/* This is temporary until subs/code refs are done..*/ +typedef void * DummyCodeRef; + + +struct _ParrotIOBuf { + size_t bufsize; + unsigned char * buf; + unsigned char * head; +}; + +struct _ParrotIO { + INTVAL fd; /* Low level OS descriptor */ + INTVAL mode; /* Read/Write/etc. */ + INTVAL flags; + INTVAL iotype; /* Type of stream is this */ + off_t filepos; /* Current real file pointer */ + INTVAL buftype; + ParrotIOBuf in; + ParrotIOBuf out; + ParrotIOLayer * stack; + /* ParrotIOFilter * filters; */ +}; + +struct _ParrotIOLayer { + void * this; /* Instance specific data */ + const char * name; + INTVAL flags; + ParrotIOLayerAPI * api; + ParrotIOLayer * up; + ParrotIOLayer * down; +}; + +#define PIO_DOWNLAYER(x) x->down +#define PIO_UPLAYER(x) x->up + +/* + * Terminal layer can't be pushed on top of other layers; + * vice-versa, non-terminal layers be pushed on an empty io stack + * An OS layer would be a terminal layer, non-terminals might be + * buffering, translation, compression or encryption layers. + */ +#define PIO_L_TERMINAL 0x0001 +#define PIO_L_FASTGETS 0x0002 + + +/* Others to come */ +extern ParrotIOLayer pio_os_layer; +#ifdef WIN32 +/*extern ParrotIOLayer pio_win32_layer; */ +#endif + +/* This is list of valid layers */ +extern ParrotIOLayer * pio_registered_layers; + +/* This is the actual (default) layer stack which is used for IO */ +extern ParrotIOLayer * pio_default_stack; + + +#ifndef theINTERP +# define theINTERP struct Parrot_Interp * interpreter +#endif + + +/* + * By default, any layer not implementing an interface (ie. leaving + * null value for a function) implicitly passes calls to the + * next layer. To override or shadow an API the layer must implement + * the specific call. + */ +struct _ParrotIOLayerAPI { + INTVAL (*Init)(theINTERP, ParrotIOLayer * l); + ParrotIOLayer * (*New)(ParrotIOLayer * proto); + void (*Delete)(ParrotIOLayer * l); + INTVAL (*Pushed)(ParrotIOLayer * l, ParrotIO * io); + INTVAL (*Popped)(ParrotIOLayer * l, ParrotIO * io); + ParrotIO * (*Open)(theINTERP, ParrotIOLayer * l, + const char * name, const char * mode); + ParrotIO * (*Open2)(theINTERP, ParrotIOLayer * l, + const char * name, const char * mode, + int perm); + ParrotIO * (*Open3)(theINTERP, ParrotIOLayer * l, + const char * name, const char * mode, + int perm, ParrotIO * io); + ParrotIO * (*Open_ASync)(theINTERP, ParrotIOLayer * l, + const char * name, const char * mode, + DummyCodeRef *); + ParrotIO * (*FDOpen)(theINTERP, ParrotIOLayer * l, + INTVAL fd, const char * name); + INTVAL (*Close)(theINTERP, ParrotIOLayer * l, + ParrotIO * io); + size_t (*Write)(theINTERP, ParrotIOLayer * l, + ParrotIO * io, const void * buf, + size_t len); + size_t (*Write_ASync)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, void * buf, size_t len, + DummyCodeRef *); + size_t (*Read)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, void * buf, size_t len); + size_t (*Read_ASync)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, void * buf, size_t len, + DummyCodeRef *); + INTVAL (*Flush)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io); + INTVAL (*Seek)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, off_t offset, + INTVAL whence); + off_t (*Tell)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io); + INTVAL (*SetBuf)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, INTVAL bufsize); + INTVAL (*SetLineBuf)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io); + INTVAL (*GetCount)(theINTERP, ParrotIOLayer * layer); + INTVAL (*Fill)(theINTERP, ParrotIOLayer * layer); + INTVAL (*PutS)(theINTERP, ParrotIOLayer * l, + ParrotIO * io, const char * s); + INTVAL (*GetS)(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, char * s, INTVAL maxlen); +}; + + +/* io.c - If you add new layers, register them in init_layers() */ +extern void PIO_init(theINTERP); +extern INTVAL PIO_init_stacks(theINTERP); +extern INTVAL PIO_push_layer(ParrotIOLayer *, ParrotIO *); +extern ParrotIOLayer * PIO_pop_layer(ParrotIO *); +extern ParrotIOLayer * PIO_copy_stack(ParrotIOLayer *); + + +extern ParrotIO * new_io_header(struct Parrot_Interp *, INTVAL, + INTVAL, INTVAL); +extern struct PMC * new_io_pmc(struct Parrot_Interp *, ParrotIO *); +extern void free_io_header(ParrotIO *); + +extern INTVAL PIO_base_init(theINTERP, ParrotIOLayer * proto); +extern ParrotIOLayer * PIO_base_new_layer(ParrotIOLayer * proto); +extern void PIO_base_delete_layer(ParrotIOLayer * proto); + +extern ParrotIO * PIO_open(theINTERP, const char *, const char *); +extern ParrotIO * PIO_fdopen(theINTERP, INTVAL, const char *); +extern INTVAL PIO_close(theINTERP, ParrotIO *); +extern void PIO_flush(theINTERP, ParrotIO *); +extern INTVAL PIO_read(theINTERP, ParrotIO *, void *, size_t); +extern INTVAL PIO_write(theINTERP, ParrotIO *, void *, size_t); +extern INTVAL PIO_setbuf(theINTERP, ParrotIO *, INTVAL); +extern INTVAL PIO_puts(theINTERP, ParrotIO *, const char *); + +#define Init_IO(x) PIO_init(x) + + + +extern ParrotIO * pio_stdin; +extern ParrotIO * pio_stdout; +extern ParrotIO * pio_stderr; + #endif diff -urN tmp/parrot/io/io.c parrot/io/io.c --- tmp/parrot/io/io.c Wed Dec 31 19:00:00 1969 +++ parrot/io/io.c Tue Jan 1 16:34:40 2002 @@ -0,0 +1,408 @@ +/* io.c + * Copyright: (When this is determined...it will go here) + * CVS Info + * Overview: + * This is the Parrot IO subsystem API. Generic IO stuff + * goes here, each specific layer goes in its own file... + * (io_os, io_buf, io_utf8, etc.) + * Data Structure and Algorithms: + * Uses the IO PMC defined in io.h + * Uses ParrotIO structs in io.h + * History: + * Initially written by Melvin Smith + * Notes: + * In future rework to use copy-on-write IO stacks rather than + * creating a new stack for each IO stream. + * Add support for loadable layers in Parrot bytecode + * References: + * Some ideas and goals from Perl5.7 and Nick Ing-Simmons' work + */ + +#include "parrot/parrot.h" + + +/* This is list of valid layers */ +ParrotIOLayer * pio_registered_layers; + +/* This is the default stack used for IO */ +ParrotIOLayer * pio_default_stack; + +/* The standard streams */ +ParrotIO * pio_stdin; +ParrotIO * pio_stdout; +ParrotIO * pio_stderr; + + +PMC * new_io_pmc(theINTERP, ParrotIO * io) { + PMC * new_pmc; + new_pmc = new_pmc_header(interpreter); + new_pmc->data = io; + new_pmc->vtable = YOU_LOSE_VTABLE; + return new_pmc; +} + +ParrotIO * new_io_header(theINTERP, INTVAL iotype, INTVAL flags, + INTVAL mode) { + ParrotIO * new_io; + new_io = (ParrotIO *)malloc(sizeof(ParrotIO)); + new_io->flags = flags; + new_io->mode = mode; + new_io->iotype = iotype; + new_io->stack = pio_default_stack; + /*new_io->buftype = PIO_BUFTYPE_FULL; */ + /*new_io->filepos = -1; */ + new_io->in.buf = NULL; + new_io->in.head = NULL; + new_io->out.buf = NULL; + new_io->out.head = NULL; + return new_io; +} + +void free_io_header(ParrotIO *io) { + if( io->in.buf ) + free(io->in.buf); + if( io->out.buf ) + free(io->out.buf); + free(io); +} + + +/* + * Initialize some stuff. + */ +void PIO_init(theINTERP) { + int err; + + /* Init IO stacks before creating any handles */ + if((err = PIO_init_stacks(interpreter)) != 0) { + abort(); + } + + /* + * Create our STDIN, STDOUT and STDERR handles + */ + pio_stdin = PIO_fdopen(interpreter, STDIN_FILENO, "<"); + pio_stdout = PIO_fdopen(interpreter, STDOUT_FILENO, ">"); + pio_stderr = PIO_fdopen(interpreter, STDERR_FILENO, ">"); + + if( !pio_stdin || !pio_stderr || !pio_stdout ) { + abort(); + } + + if((interpreter->flags & PARROT_DEBUG_FLAG) != 0) { + PIO_puts(interpreter, pio_stderr, + "PIO: IO system initialized.\n"); + } +} + + +/* + * Initialize the default IO stack(s) + */ +INTVAL PIO_init_stacks(theINTERP) { + ParrotIOLayer * p; + PIO_push_layer(&pio_os_layer, NULL); + /*PIO_push_layer(&pio_stdio_layer, NULL);*/ + + for(p=pio_default_stack; p; p=p->down) { + if( p->api->Init ) { + if((*p->api->Init)(interpreter, p) != 0) { + if((interpreter->flags & PARROT_DEBUG_FLAG) != 0) { +#if 0 + fprintf(stderr, + "Parrot IO: Failed init layer(%s).\n", +p->name); +#endif + /* abort(); */ + } + } + } + } + return 0; +} + + +/* + * Init routine called once for each layer at interpreter creation + * time. This is similar to a Perl module INIT {} block. + */ +INTVAL PIO_base_init(theINTERP, ParrotIOLayer * proto) { + return 0; +} + +/* + * ParrotIOLayer constructor with optional copy + */ +ParrotIOLayer * PIO_base_new_layer(ParrotIOLayer * proto) { + ParrotIOLayer * new_layer; + + new_layer = mem_sys_allocate(sizeof(ParrotIOLayer)); + if( proto ) { + /* FIXME: Flag here to indicate whether to free strings */ + new_layer->name = proto->name; + new_layer->flags = proto->flags; + new_layer->api = proto->api; + } else { + new_layer->name = NULL; + new_layer->flags = 0; + new_layer->api = NULL; + } + new_layer->this = 0; + new_layer->up = NULL; + new_layer->down = NULL; + return new_layer; +} + + +/* + * ParrotIOLayer object destructor + */ +void PIO_base_delete_layer(ParrotIOLayer * layer) { + if( layer != NULL ) + free(layer); +} + + +/* + * Push a layer onto an IO object or the default stack + */ +INTVAL PIO_push_layer(ParrotIOLayer * layer, ParrotIO * io) { + if( !layer ) + return -1; + if( io ) { + if( !io->stack + && (layer->flags & PIO_L_TERMINAL) == 0 ) { + /* Error( 1st layer must be terminal) */ + return -1; + } + layer->down = io->stack; + if( io->stack ) + io->stack->up = layer; + io->stack = layer; + if( layer->api->Pushed ) + (*layer->api->Pushed)(layer, io); + } else { + if( !pio_default_stack + && (layer->flags & PIO_L_TERMINAL) == 0 ) { + /* Error( 1st layer must be terminal) */ + return -1; + } + layer->down = pio_default_stack; + if( pio_default_stack ) + pio_default_stack->up = layer; + pio_default_stack = layer; + return 0; + } + return -1; +} + + +/* + * Pop a layer from an IO object or the default stack + */ +ParrotIOLayer * PIO_pop_layer(ParrotIO * io) { + ParrotIOLayer * layer; + if( io ) { + layer = io->stack; + if( layer ) { + io->stack = layer->down; + io->stack->up = 0; + layer->up = 0; + layer->down = 0; + if( layer->api->Popped ) + (*layer->api->Popped)(layer, io); + return layer; + } + return layer; + } + /* Null io object - use default stack */ + else { + layer = pio_default_stack; + if( layer ) { + pio_default_stack = layer->down; + pio_default_stack->up = NULL; + layer->up = 0; + layer->down = 0; + return layer; + } + } + + return 0; +} + + +/* + * Primarily used to copy the default IO stack for a new + * IO object. Later we will do some funky copy-on-write stuff. + */ +ParrotIOLayer * PIO_copy_stack( ParrotIOLayer * stack ) { + ParrotIOLayer * new_stack; + ParrotIOLayer ** ptr_new; + ParrotIOLayer * ptr_proto; + ParrotIOLayer * ptr_last = NULL; + ptr_new = &new_stack; + ptr_proto = stack; + while( ptr_proto ) { + *ptr_new = PIO_base_new_layer( ptr_proto ); + (*ptr_new)->up = ptr_last; + ptr_proto = ptr_proto->down; + ptr_last = *ptr_new; + ptr_new = &((*ptr_new)->down); + } + + return new_stack; +} + + +/* + * Generic top level ParrotIO interface. + */ + + +/* + * API for controlling buffering specifics on an IO stream + */ +INTVAL PIO_setbuf(theINTERP, ParrotIO * io, INTVAL bufsize) { + ParrotIOLayer * l = io->stack; + PIO_flush(interpreter, io); + while(l) { + if(l->api->SetBuf) { + return (*l->api->SetBuf)(interpreter, l, + io, bufsize); + } + l = PIO_DOWNLAYER(l); + } + + return 0; +} + + +ParrotIO * PIO_open(theINTERP, const char * spath, const char * smode) { + ParrotIO * io; + ParrotIOLayer * l = pio_default_stack; + while(l) { + if(l->api->Open) { + io = (*l->api->Open)(interpreter, l, spath, + smode); + io->stack = pio_default_stack; + return io; + } + l = PIO_DOWNLAYER(l); + } + return NULL; +} + + +/* + * Create an IO object on an existing, open file descriptor. + * This is particularly used to init Parrot Standard IO onto + * the OS IO handles (0,1,2). + */ +ParrotIO * PIO_fdopen(theINTERP, INTVAL fd, const char * smode) { + ParrotIO * io; + ParrotIOLayer * l = pio_default_stack; + while(l) { + if(l->api->FDOpen) { + io = (*l->api->FDOpen)(interpreter, l, fd, + smode); + io->stack = pio_default_stack; + return io; + } + l = PIO_DOWNLAYER(l); + } + return NULL; +} + + +INTVAL PIO_close(theINTERP, ParrotIO * io) { + if( io ) { + ParrotIOLayer * l = io->stack; + while(l) { + if(l->api->Close) { + PIO_flush(interpreter, io); + (*l->api->Close)(interpreter, l, io); + return; + } + l = PIO_DOWNLAYER(l); + } + } + return 0; +} + + +void PIO_flush(theINTERP, ParrotIO * io) { + if( io ) { + ParrotIOLayer * l = io->stack; + while(l) { + if( l->api->Flush ) { + (*l->api->Flush)(interpreter, l, io); + return; + } + l = PIO_DOWNLAYER(l); + } + } +} + + +/* + * Iterate down the stack to the first layer implementing "Read" API + */ +INTVAL PIO_read(theINTERP, ParrotIO * io, void * buffer, size_t len) { + if( io ) { + ParrotIOLayer * l = io->stack; + while(l) { + if( l->api->Read ) { + return (*l->api->Read)(interpreter, + l, io, buffer, len); + } + l = PIO_DOWNLAYER(l); + } + } + + return 0; +} + + +/* + * Iterate down the stack to the first layer implementing "Write" API + */ +INTVAL PIO_write(theINTERP, ParrotIO * io, void * buffer, size_t len) { + if( io ) { + ParrotIOLayer * l = io->stack; + while(l) { + if( l->api->Write ) { + return (*l->api->Write)(interpreter, + l, io, buffer, len); + } + l = PIO_DOWNLAYER(l); + } + } + + return 0; +} + + +INTVAL PIO_puts(theINTERP, ParrotIO * io, const char * s) { + if( io ) { + ParrotIOLayer * l = io->stack; + while(l) { + if( l->api->PutS ) { + return (*l->api->PutS)(interpreter, + l, io, s); + } + l = PIO_DOWNLAYER(l); + } + } + + return -1; +} + + +/* + * Local variables: + * c-indentation-style: bsd + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: +*/ diff -urN tmp/parrot/io/io_os.c parrot/io/io_os.c --- tmp/parrot/io/io_os.c Wed Dec 31 19:00:00 1969 +++ parrot/io/io_os.c Tue Jan 1 16:36:55 2002 @@ -0,0 +1,282 @@ +/* io_os.c + * Copyright: (When this is determined...it will go here) + * CVS Info + * Overview: + * This is the Parrot IO UNIX layer. May be changed to be + * the "generic OS" layer when we see how much we can share + * between platforms without smudging... + * For UNIX systems (and some others) this is the low level + * OS layer (unbuffered). + * Data Structure and Algorithms: + * History: + * Initially written by Melvin Smith + * Notes: + * References: + */ + +#include "parrot/parrot.h" + +/* Defined at bottom */ +extern ParrotIOLayerAPI pio_os_layer_api; + +ParrotIOLayer pio_os_layer = { + NULL, + "os", + PIO_L_TERMINAL, + &pio_os_layer_api, + 0, 0 +}; + + +/* + * Currently keeping layer prototypes local to each layer + * file. + */ + +ParrotIO * PIO_os_open(theINTERP, ParrotIOLayer * layer, + const char * spath, const char * smode); +ParrotIO * PIO_os_fdopen(theINTERP, ParrotIOLayer * layer, + INTVAL fd, const char * smode); +INTVAL PIO_os_close(theINTERP, ParrotIOLayer * layer, + ParrotIO * io); +void PIO_os_flush(theINTERP, ParrotIOLayer * layer, + ParrotIO * io); +size_t PIO_os_read(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, void * buffer, size_t len); +size_t PIO_os_write(theINTERP, ParrotIOLayer * layer, + ParrotIO * io, const void * buffer, size_t len); +INTVAL PIO_os_puts(theINTERP, ParrotIOLayer * l, ParrotIO * io, + const char * s); + + + + +/* + * Open modes (read, write, append, etc.) are done in pseudo-Perl + * style using <, >, etc. + */ +ParrotIO * PIO_os_open(theINTERP, ParrotIOLayer * layer, + const char * spath, const char * smode) { + ParrotIO * io; + int flags, type, mode, fd; + const char * modeptr; + type = PIO_TYPE_FILE; + flags = 0; + mode = DEFAULT_OPEN_MODE; + modeptr = smode; +#if 0 + if((interpreter->flags & PARROT_DEBUG_FLAG) != 0) { + fprintf(stderr, "PIO_os_open: %s, %s\n", + spath, modeptr); + } +#endif + /* Set mode flags - <, >, >>, +<, +> */ + /* add ? and ! for block/non-block */ + switch(*modeptr) { + case '+': + flags = O_RDWR; + break; + case '<': + flags = O_RDONLY; + break; + case '>': + flags = O_WRONLY | O_CREAT; + if( *(++modeptr) == '>') + flags |= O_APPEND; + else if(*modeptr != 0) + return 0; + else flags |= O_TRUNC; + break; + default: + return 0; + } + + if((fd = open((const char *)spath, flags, mode)) != -1 ){ + io = new_io_header(interpreter, type, flags, mode); + io->fd = fd; + return io; + } else { + /* Error.. */ + if((interpreter->flags & PARROT_DEBUG_FLAG) != 0) { + char * errstr = strerror( errno ); +#if 0 + fprintf(stderr, "PIO_os_open: %s", + errstr ); +#endif + } + return 0; + } + + return 0; +} + + +ParrotIO * PIO_os_fdopen(theINTERP, ParrotIOLayer * layer, + INTVAL fd, const char * smode) { + ParrotIO * io; + INTVAL flags, mode; + flags = 0; + mode = 0; + + /* FIXME - Check file handle specifics, validity */ + /* Need to make this portable, I haven't checked this + * on non-UNIX. + */ +#if 1 + /* Get descriptor flags */ + if((flags = fcntl(fd, F_GETFL, 0)) >= 0) { + /*int accmode = flags & O_ACCMODE;*/ + /* Check other flags (APPEND, ASYNC, etc) */ + } else { + /* Probably invalid descriptor */ + return NULL; + } +#endif + io = new_io_header(interpreter, PIO_TYPE_FILE, flags, mode); + io->fd = fd; + io->buftype = PIO_BUFTYPE_NONE; + return io; +} + + +INTVAL PIO_os_close(theINTERP, ParrotIOLayer * layer, ParrotIO * io) { +#if 0 + if((interpreter->flags & PARROT_DEBUG_FLAG) != 0) { + fprintf(stderr, "PIO_os_close: %d\n", (int)io->fd ); + } +#endif + close( io->fd ); + io->fd = -1; + return 0; +} + + +/* At lowest layer all we can do for flush is ask kernel to sync(). + * How portable is fsync() ? It is POSIX at least. + * Can also be accomplished by O_SYNC on file handle. + */ +void PIO_os_flush(theINTERP, ParrotIOLayer * layer, ParrotIO * io) { +#if 0 + /* UNIX and VMS have fsync, does win32? */ + fsync(io->fd); +#endif +} + + +size_t PIO_os_read(theINTERP, ParrotIOLayer * layer, ParrotIO * io, + void * buffer, size_t len) { + int bytes; + for(;;) { + bytes = read(io->fd, buffer, len); + if( bytes > 0 ) + return bytes; + else if( bytes < 0 ) { + switch(errno) { + case EINTR: continue; + default: return bytes; + } + } else { + /* Set EOF flag */ + return bytes; + } + } + return bytes; +} + + +size_t PIO_os_write(theINTERP, ParrotIOLayer * layer, ParrotIO * io, + const void * buffer, size_t len) { + int err; + int bytes; + size_t to_write; + const char * ptr; +#if 0 + if((interpreter->flags & PARROT_DEBUG_FLAG) != 0) { + fprintf(stderr, "ParrotIO_os_write(fd=%d): %d bytes\n", + io->fd, len ); + } +#endif + ptr = buffer; + to_write = len; + bytes = 0; + + write_through: + while(to_write > 0) { + if((err = write(io->fd, ptr, to_write)) >= 0 ) { + ptr += err; + to_write -= err; + bytes += err; +#if 0 + fprintf(stderr, "ParrotIO_os_write: wrote %d +bytes\n", err ); +#endif + } else { + switch(errno) { + case EINTR: goto write_through; +#ifdef EAGAIN + case EAGAIN: return bytes; +#endif + } + } + } + return bytes; +} + + +INTVAL PIO_os_puts(theINTERP, ParrotIOLayer * l, ParrotIO * io, + const char * s) { + size_t len; + len = strlen(s); + if( len > 0 ) { + size_t sz; + sz = PIO_os_write(interpreter, l, io, s, len); + if( sz < len ) { + return -1; + } else { + return len; + } + } + + return -1; +} + + + +ParrotIOLayerAPI pio_os_layer_api = { + PIO_base_init, + PIO_base_new_layer, + PIO_base_delete_layer, + NULL, + NULL, + PIO_os_open, + NULL, + NULL, + NULL, + PIO_os_fdopen, + PIO_os_close, + PIO_os_write, + NULL, + PIO_os_read, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + PIO_os_puts, + NULL +}; + + + +/* + * Local variables: + * c-indentation-style: bsd + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: expandtab shiftwidth=4: +*/ +