parrotcode: Parrot sprintf | |
Contents | C |
src/spf_vtable.c - Parrot sprintf
Implements the two families of functions Parrot_sprintf
may use to retrieve arguments.
*/
#define IN_SPF_SYSTEM
#include "parrot/parrot.h"
#include <stdarg.h> #include "spf_vtable.str"
/* HEADERIZER HFILE: none */
/* HEADERIZER BEGIN: static */
PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT static STRING * getchr_pmc( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT static STRING * getchr_va( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT static HUGEFLOATVAL getfloat_pmc( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT static HUGEFLOATVAL getfloat_va( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT static HUGEINTVAL getint_pmc( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT static HUGEINTVAL getint_va( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static void * getptr_pmc( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT PARROT_CAN_RETURN_NULL static void * getptr_va( PARROT_INTERP, SHIM(INTVAL size), NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static STRING * getstring_pmc( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static STRING * getstring_va( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT static UHUGEINTVAL getuint_pmc( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
PARROT_WARN_UNUSED_RESULT static UHUGEINTVAL getuint_va( PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj) ) __attribute__nonnull__(1) __attribute__nonnull__(3);
/* HEADERIZER END: static */
/*
FUNCDOC: getchr_va
Gets a char
out of the va_list
in obj
and returns it as a Parrot STRING
.
size
is unused.
*/
PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT static STRING * getchr_va(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { va_list *arg = (va_list *)(obj->data);
/* char promoted to int */
char ch = (char)va_arg(*arg, int);
return string_make(interp, &ch, 1, "iso-8859-1", 0);
}
/*
FUNCDOC: getint_va
Gets an integer out of the va_list
in obj
and returns it as a Parrot STRING
.
size
is an enum spf_type_t
value which indicates the storage type of the integer.
*/
PARROT_WARN_UNUSED_RESULT static HUGEINTVAL getint_va(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { va_list * const arg = (va_list *)(obj->data);
switch (size) {
case SIZE_REG:
return va_arg(*arg, int);
case SIZE_SHORT:
/* "'short int' is promoted to 'int' when passed through '...'" */
return (short)va_arg(*arg, int);
case SIZE_LONG:
return va_arg(*arg, long);
case SIZE_HUGE:
return va_arg(*arg, HUGEINTVAL);
case SIZE_XVAL:
return va_arg(*arg, INTVAL);
case SIZE_OPCODE:
return va_arg(*arg, opcode_t);
case SIZE_PMC:{
PMC * const pmc = (PMC *)va_arg(*arg, PMC *);
return VTABLE_get_integer(interp, pmc);
}
default:
PANIC(interp, "Invalid int type!");
}
}
/*
FUNCDOC: getuint_va
Gets an unsigned integer out of the va_list
in obj
and returns it as a Parrot STRING
.
size
is an enum spf_type_t
value which indicates the storage type of the integer.
*/
PARROT_WARN_UNUSED_RESULT static UHUGEINTVAL getuint_va(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { va_list * const arg = (va_list *)(obj->data);
switch (size) {
case SIZE_REG:
return va_arg(*arg, unsigned int);
case SIZE_SHORT:
/* short int promoted HLAGHLAGHLAGH. See note above */
return (unsigned short)va_arg(*arg, unsigned int);
case SIZE_LONG:
return va_arg(*arg, unsigned long);
case SIZE_HUGE:
return va_arg(*arg, UHUGEINTVAL);
case SIZE_XVAL:
return va_arg(*arg, UINTVAL);
case SIZE_OPCODE:
return va_arg(*arg, opcode_t);
case SIZE_PMC:{
PMC *pmc = va_arg(*arg, PMC *);
return (UINTVAL)VTABLE_get_integer(interp, pmc);
}
default:
PANIC(interp, "Invalid uint type!");
}
}
/*
FUNCDOC: getfloat_va
Gets an floating-point number out of the va_list
in obj
and returns it as a Parrot STRING
.
size
is an enum spf_type_t
value which indicates the storage type of the number.
*/
PARROT_WARN_UNUSED_RESULT static HUGEFLOATVAL getfloat_va(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { va_list * const arg = (va_list *)(obj->data);
switch (size) {
case SIZE_SHORT:
/* float is promoted to double */
return (HUGEFLOATVAL)(float)va_arg(*arg, double);
case SIZE_REG:
return (HUGEFLOATVAL)(double)va_arg(*arg, double);
case SIZE_HUGE:
return (HUGEFLOATVAL)(HUGEFLOATVAL)
va_arg(*arg, HUGEFLOATVAL);
case SIZE_XVAL:
return (HUGEFLOATVAL)(FLOATVAL)
va_arg(*arg, FLOATVAL);
case SIZE_PMC:{
PMC * const pmc = (PMC *)va_arg(*arg, PMC *);
return (HUGEFLOATVAL)(VTABLE_get_number(interp, pmc));
}
default:
real_exception(interp, NULL, INVALID_CHARACTER,
"Internal sprintf doesn't recognize size %d for a float",
size);
return (HUGEFLOATVAL)0.0;
}
}
/*
FUNCDOC: getstring_va
Gets an string out of the va_list
in obj
and returns it as a Parrot STRING
.
size
is an enum spf_type_t
value which indicates the storage type of the string.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static STRING * getstring_va(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { va_list * const arg = (va_list *)(obj->data);
switch (size) {
case SIZE_REG:
{
const char * const cstr = (char *)va_arg(*arg, char *);
return cstr2pstr(cstr);
}
case SIZE_PSTR:
{
STRING * const s = (STRING *)va_arg(*arg, STRING *);
return s ? s : CONST_STRING(interp, "(null)");
}
case SIZE_PMC:
{
PMC * const pmc = (PMC *)va_arg(*arg, PMC *);
STRING * const s = VTABLE_get_string(interp, pmc);
return s;
}
default:
real_exception(interp, NULL, INVALID_CHARACTER,
"Internal sprintf doesn't recognize size %d for a string",
size);
}
}
/*
FUNCDOC: getptr_va
Gets a void *
out of the va_list
in obj
and returns it.
size
is unused.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CAN_RETURN_NULL static void * getptr_va(PARROT_INTERP, SHIM(INTVAL size), NOTNULL(SPRINTF_OBJ *obj)) { va_list * const arg = (va_list *)(obj->data);
return (void *)va_arg(*arg, void *);
}
SPRINTF_OBJ va_core = { NULL, 0, getchr_va, getint_va, getuint_va, getfloat_va, getstring_va, getptr_va };
/*
FUNCDOC: getchr_pmc
Same as getchr_va()
except that a vtable is used to get the value from obj
.
*/
PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT static STRING * getchr_pmc(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { STRING *s; PMC * const tmp = VTABLE_get_pmc_keyed_int(interp, ((PMC *)obj->data), (obj->index));
obj->index++;
s = VTABLE_get_string(interp, tmp);
/* XXX string_copy like below? + adjusting bufused */
return string_substr(interp, s, 0, 1, NULL, 0);
}
/*
FUNCDOC: getint_pmc
Same as getint_va()
except that a vtable is used to get the value from obj
.
*/
PARROT_WARN_UNUSED_RESULT static HUGEINTVAL getint_pmc(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { HUGEINTVAL ret; PMC * const tmp = VTABLE_get_pmc_keyed_int(interp, ((PMC *)obj->data), (obj->index));
obj->index++;
ret = VTABLE_get_integer(interp, tmp);
switch (size) {
case SIZE_SHORT:
ret = (short)ret;
break;
/* case SIZE_REG: ret=(HUGEINTVAL)(int)ret; break; */
case SIZE_LONG:
ret = (long)ret;
break;
default:
/* nothing */ ;
}
return ret;
}
/*
FUNCDOC: getuint_pmc
Same as getuint_va()
except that a vtable is used to get the value from obj
.
*/
PARROT_WARN_UNUSED_RESULT static UHUGEINTVAL getuint_pmc(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { UHUGEINTVAL ret; PMC * const tmp = VTABLE_get_pmc_keyed_int(interp, ((PMC *)obj->data), (obj->index));
obj->index++;
ret = (UINTVAL)VTABLE_get_integer(interp, tmp);
switch (size) {
case SIZE_SHORT:
ret = (unsigned short)ret;
break;
/* case SIZE_REG: * ret=(UHUGEINTVAL)(unsigned int)ret; * break; */
case SIZE_LONG:
ret = (unsigned long)ret;
break;
default:
/* nothing */ ;
}
return ret;
}
/*
FUNCDOC: getfloat_pmc
Same as getfloat_va()
except that a vtable is used to get the value from obj
.
*/
PARROT_WARN_UNUSED_RESULT static HUGEFLOATVAL getfloat_pmc(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { HUGEFLOATVAL ret; PMC * const tmp = VTABLE_get_pmc_keyed_int(interp, ((PMC *)obj->data), (obj->index));
obj->index++;
ret = (HUGEFLOATVAL)(VTABLE_get_number(interp, tmp));
switch (size) {
case SIZE_SHORT:
ret = (HUGEFLOATVAL)(float)ret;
break;
/* case SIZE_REG: * ret=(HUGEFLOATVAL)(double)ret; * break; */
default:
/* nothing */ ;
}
return ret;
}
/*
FUNCDOC: getstring_pmc
Same as getstring_va()
except that a vtable is used to get the value from obj
.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static STRING * getstring_pmc(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { STRING *s; PMC * const tmp = VTABLE_get_pmc_keyed_int(interp, ((PMC *)obj->data), (obj->index));
obj->index++;
s = (STRING *)(VTABLE_get_string(interp, tmp));
return s;
}
/*
FUNCDOC: getptr_pmc
Same as getptr_va()
except that a vtable is used to get the value from obj
.
*/
PARROT_WARN_UNUSED_RESULT PARROT_CANNOT_RETURN_NULL static void * getptr_pmc(PARROT_INTERP, INTVAL size, NOTNULL(SPRINTF_OBJ *obj)) { PMC * const tmp = VTABLE_get_pmc_keyed_int(interp, ((PMC *)obj->data), (obj->index)); INTVAL i = VTABLE_get_integer(interp, tmp);
obj->index++;
/* XXX correct? */
return (void *)i;
}
SPRINTF_OBJ pmc_core = { NULL, 0, getchr_pmc, getint_pmc, getuint_pmc, getfloat_pmc, getstring_pmc, getptr_pmc };
/*
src/misc.h, src/misc.c, src/spf_render.c.
When I was first working on this implementation of sprintf, I ran into a problem. I wanted to re-use the implementation for a Parrot bytecode-level sprintf, but that couldn't be done, since it used va_*
directly. For a while I thought about generating two versions of the source with a Perl script, but that seemed like overkill. Eventually I came across this idea -- pass in a specialized vtable with methods for extracting things from the arglist, whatever it happened to be. This is the result.
In the future, it may be deemed desirable to similarly vtable-ize appending things to the string, allowing for faster PIO_printf()
&c, as well as a version that writes directly to a C string. However, at this point neither of those is needed.
*/
/* * Local variables: * c-file-style: "parrot" * End: * vim: expandtab shiftwidth=4: */
|