parrotcode: IO Layer Handling | |
Contents | C |
src/io/io_layers.c - IO Layer Handling
The Parrot IO subsystem uses a per-interpreter stack to provide a layer-based approach to IO.
Each layer implements a subset of the ParrotIOLayerAPI
vtable.
To find an IO function the layer stack is searched downwards until a non-NULL
function pointer is found for that particular slot.
FUNCDOC: PIO_base_new_layer
The default IO layer constructor.
Creates and returns a new ParrotIOLayer
.
If a prototype *proto
is supplied then its values will be copied to the new instance.
*/
#include "parrot/parrot.h" #include "parrot/io.h" #include "io_private.h"
/* HEADERIZER HFILE: include/parrot/io.h */
PARROT_API PARROT_MALLOC PARROT_CANNOT_RETURN_NULL ParrotIOLayer * PIO_base_new_layer(NULLOK(ParrotIOLayer *proto)) { ParrotIOLayer * const new_layer = mem_allocate_typed(ParrotIOLayer);
/*
* XXX use managed memory here ?
*/
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->self = 0;
new_layer->up = NULL;
new_layer->down = NULL;
return new_layer;
}
/*
PIO_base_delete_layer
The default IO layer destructor. Frees the memory associated with *layer
.
*/
PARROT_API void PIO_base_delete_layer(NULLOK(ParrotIOLayer *layer)) { if (layer != NULL) mem_sys_free(layer); }
/*
FUNCDOC: PIO_push_layer
Push a layer onto an IO object (*pmc
) or the default stack.
FUNCDOC: PIO_push_layer_str
Push a layer onto an IO object (*pmc
).
*/
PARROT_API INTVAL PIO_push_layer(PARROT_INTERP, NULLOK(PMC *pmc), NULLOK(ParrotIOLayer *layer)) { if (layer == NULL) return -1;
if (!PMC_IS_NULL(pmc)) {
ParrotIOLayer *t;
ParrotIO * const io = PMC_data_typed(pmc, ParrotIO *);
if (!io)
return -1;
/* Error( 1st layer must be terminal) */
if (io->stack == NULL && (layer->flags & PIO_L_TERMINAL) == 0)
return -1;
/* Check and see if this layer already is on stack
* This is a internals sanity check not a user level
* check, at least until I fix copy-on-write stacks.
* -Melvin
*/
for (t = io->stack; t; t = t->down) {
if (t == layer)
return -1;
}
/* if this is a global layer create a copy first */
if (!(io->stack->flags & PIO_L_LAYER_COPIED))
io->stack = PIO_copy_stack(io->stack);
layer->down = io->stack;
if (io->stack)
io->stack->up = layer;
io->stack = layer;
PMC_struct_val(pmc) = layer;
if (layer->api->Pushed)
(*layer->api->Pushed) (layer, io);
}
else {
ParrotIOLayer *t;
ParrotIOData * const d = interp->piodata;
if (d->default_stack == NULL && (layer->flags & PIO_L_TERMINAL) == 0) {
/* Error( 1st layer must be terminal) */
return -1;
}
/* Sanity check */
for (t = d->default_stack; t; t = t->down) {
if (t == layer)
return -1;
}
layer->down = d->default_stack;
if (d->default_stack)
d->default_stack->up = layer;
d->default_stack = layer;
return 0;
}
return -1;
}
PARROT_WARN_UNUSED_RESULT PARROT_CAN_RETURN_NULL PARROT_API ParrotIOLayer * PIO_get_layer(SHIM_INTERP, NOTNULL(const char *name)) { ParrotIOLayer **t;
for (t = pio_registered_layers; *t; ++t)
if (strcmp(name, (*t)->name) == 0)
return *t;
return NULL;
}
void PIO_push_layer_str(PARROT_INTERP, NOTNULL(PMC *pmc), NULLOK(STRING *ls)) { char * const cls = string_to_cstring(interp, ls); ParrotIOLayer * const l = PIO_get_layer(interp, cls); ParrotIOLayer * newlayer;
string_cstring_free(cls);
if (!l)
real_exception(interp, NULL, 1, "Layer not found");
/* make private copy */
newlayer = PIO_base_new_layer(l);
newlayer->flags |= PIO_L_LAYER_COPIED;
PIO_push_layer(interp, pmc, newlayer);
}
/*
FUNCDOC: PIO_pop_layer
Pop a layer from an IO object (*pmc
) or the default stack.
FUNCDOC: PIO_pop_layer_str
Pop a layer from an IO object (*pmc
) and return the name of the popped layer. The layer gets freed.
*/
PARROT_API PARROT_IGNORABLE_RESULT PARROT_CAN_RETURN_NULL ParrotIOLayer * PIO_pop_layer(PARROT_INTERP, NULLOK(PMC *pmc)) { ParrotIO * const io = PMC_data_typed(pmc, ParrotIO *);
if (!PMC_IS_NULL(pmc)) {
ParrotIOLayer *layer;
if (!io)
return 0;
/* if this is a global layer create a copy first */
if (!(io->stack->flags & PIO_L_LAYER_COPIED))
io->stack = PIO_copy_stack(io->stack);
layer = io->stack;
if (layer) {
io->stack = layer->down;
PMC_struct_val(pmc) = io->stack;
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 {
ParrotIOData * const d = interp->piodata;
ParrotIOLayer * const layer = d->default_stack;
if (layer) {
d->default_stack = layer->down;
d->default_stack->up = NULL;
layer->up = 0;
layer->down = 0;
return layer;
}
}
return NULL;
}
PARROT_IGNORABLE_RESULT PARROT_CANNOT_RETURN_NULL STRING * PIO_pop_layer_str(PARROT_INTERP, NOTNULL(PMC *pmc)) { ParrotIOLayer * const layer = PIO_pop_layer(interp, pmc); STRING * const ls = string_make(interp, layer->name, strlen(layer->name), "iso-8859-1", 0); mem_sys_free(layer); return ls; }
/*
FUNCDOC: PIO_copy_stack
Primarily used to copy the default IO stack for a new IO object. Later we will do some funky copy-on-write stuff.
*/
PARROT_API PARROT_IGNORABLE_RESULT PARROT_CANNOT_RETURN_NULL ParrotIOLayer * PIO_copy_stack(NULLOK(ParrotIOLayer *stack)) { ParrotIOLayer *ptr_new = NULL; ParrotIOLayer *ptr_last = NULL; ParrotIOLayer **ptr_ptr_new = &ptr_new;
while (stack) {
*ptr_ptr_new = PIO_base_new_layer(stack);
(*ptr_ptr_new)->flags |= PIO_L_LAYER_COPIED;
(*ptr_ptr_new)->up = ptr_last;
stack = stack->down;
ptr_last = *ptr_ptr_new;
ptr_ptr_new = &((*ptr_ptr_new)->down);
}
return ptr_new;
}
/* * Local variables: * c-file-style: "parrot" * End: * vim: expandtab shiftwidth=4: */
|