NAME ^

src/spf_vtable.c - Parrot sprintf

DESCRIPTION ^

Implements the two families of functions Parrot_sprintf may use to retrieve arguments.

Var args Functions ^

*/

#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 };

/*

PMC Functions ^

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 };

/*

SEE ALSO ^

src/misc.h, src/misc.c, src/spf_render.c.

HISTORY ^

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.

TODO ^

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: */


parrot