2 Copyright (C) 2001-2009, Parrot Foundation.
7 src/spf_vtable.c - Parrot sprintf
11 Implements the two families of functions C<Parrot_sprintf> may use to
14 =head2 Var args Functions
24 #include "parrot/parrot.h"
27 #include "spf_vtable.str"
29 /* HEADERIZER HFILE: none */
31 /* HEADERIZER BEGIN: static */
32 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
34 PARROT_CANNOT_RETURN_NULL
35 PARROT_WARN_UNUSED_RESULT
36 static STRING
* getchr_pmc(PARROT_INTERP
,
38 ARGMOD(SPRINTF_OBJ
*obj
))
39 __attribute__nonnull__(1)
40 __attribute__nonnull__(3)
43 PARROT_CANNOT_RETURN_NULL
44 PARROT_WARN_UNUSED_RESULT
45 static STRING
* getchr_va(PARROT_INTERP
,
47 ARGIN(SPRINTF_OBJ
*obj
))
48 __attribute__nonnull__(1)
49 __attribute__nonnull__(3);
51 PARROT_WARN_UNUSED_RESULT
52 static HUGEFLOATVAL
getfloat_pmc(PARROT_INTERP
,
54 ARGIN(SPRINTF_OBJ
*obj
))
55 __attribute__nonnull__(1)
56 __attribute__nonnull__(3);
58 PARROT_WARN_UNUSED_RESULT
59 static HUGEFLOATVAL
getfloat_va(PARROT_INTERP
,
61 ARGIN(SPRINTF_OBJ
*obj
))
62 __attribute__nonnull__(1)
63 __attribute__nonnull__(3);
65 PARROT_WARN_UNUSED_RESULT
66 static HUGEINTVAL
getint_pmc(PARROT_INTERP
,
68 ARGIN(SPRINTF_OBJ
*obj
))
69 __attribute__nonnull__(1)
70 __attribute__nonnull__(3);
72 PARROT_WARN_UNUSED_RESULT
73 static HUGEINTVAL
getint_va(PARROT_INTERP
,
75 ARGIN(SPRINTF_OBJ
*obj
))
76 __attribute__nonnull__(1)
77 __attribute__nonnull__(3);
79 PARROT_WARN_UNUSED_RESULT
80 PARROT_CANNOT_RETURN_NULL
81 static void * getptr_pmc(PARROT_INTERP
,
83 ARGIN(SPRINTF_OBJ
*obj
))
84 __attribute__nonnull__(1)
85 __attribute__nonnull__(3);
87 PARROT_WARN_UNUSED_RESULT
88 PARROT_CAN_RETURN_NULL
89 static void * getptr_va(SHIM_INTERP
,
91 ARGIN(SPRINTF_OBJ
*obj
))
92 __attribute__nonnull__(3);
94 PARROT_WARN_UNUSED_RESULT
95 PARROT_CANNOT_RETURN_NULL
96 static STRING
* getstring_pmc(PARROT_INTERP
,
98 ARGIN(SPRINTF_OBJ
*obj
))
99 __attribute__nonnull__(1)
100 __attribute__nonnull__(3);
102 PARROT_WARN_UNUSED_RESULT
103 PARROT_CANNOT_RETURN_NULL
104 static STRING
* getstring_va(PARROT_INTERP
,
106 ARGIN(SPRINTF_OBJ
*obj
))
107 __attribute__nonnull__(1)
108 __attribute__nonnull__(3);
110 PARROT_WARN_UNUSED_RESULT
111 static UHUGEINTVAL
getuint_pmc(PARROT_INTERP
,
113 ARGIN(SPRINTF_OBJ
*obj
))
114 __attribute__nonnull__(1)
115 __attribute__nonnull__(3);
117 PARROT_WARN_UNUSED_RESULT
118 static UHUGEINTVAL
getuint_va(PARROT_INTERP
,
120 ARGIN(SPRINTF_OBJ
*obj
))
121 __attribute__nonnull__(1)
122 __attribute__nonnull__(3);
124 #define ASSERT_ARGS_getchr_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
125 PARROT_ASSERT_ARG(interp) \
126 , PARROT_ASSERT_ARG(obj))
127 #define ASSERT_ARGS_getchr_va __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
128 PARROT_ASSERT_ARG(interp) \
129 , PARROT_ASSERT_ARG(obj))
130 #define ASSERT_ARGS_getfloat_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
131 PARROT_ASSERT_ARG(interp) \
132 , PARROT_ASSERT_ARG(obj))
133 #define ASSERT_ARGS_getfloat_va __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
134 PARROT_ASSERT_ARG(interp) \
135 , PARROT_ASSERT_ARG(obj))
136 #define ASSERT_ARGS_getint_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
137 PARROT_ASSERT_ARG(interp) \
138 , PARROT_ASSERT_ARG(obj))
139 #define ASSERT_ARGS_getint_va __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
140 PARROT_ASSERT_ARG(interp) \
141 , PARROT_ASSERT_ARG(obj))
142 #define ASSERT_ARGS_getptr_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
143 PARROT_ASSERT_ARG(interp) \
144 , PARROT_ASSERT_ARG(obj))
145 #define ASSERT_ARGS_getptr_va __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
146 PARROT_ASSERT_ARG(obj))
147 #define ASSERT_ARGS_getstring_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
148 PARROT_ASSERT_ARG(interp) \
149 , PARROT_ASSERT_ARG(obj))
150 #define ASSERT_ARGS_getstring_va __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
151 PARROT_ASSERT_ARG(interp) \
152 , PARROT_ASSERT_ARG(obj))
153 #define ASSERT_ARGS_getuint_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
154 PARROT_ASSERT_ARG(interp) \
155 , PARROT_ASSERT_ARG(obj))
156 #define ASSERT_ARGS_getuint_va __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
157 PARROT_ASSERT_ARG(interp) \
158 , PARROT_ASSERT_ARG(obj))
159 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
160 /* HEADERIZER END: static */
164 =item C<static STRING * getchr_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ *obj)>
166 Gets a C<char> out of the C<va_list> in C<obj> and returns it as a
175 PARROT_CANNOT_RETURN_NULL
176 PARROT_WARN_UNUSED_RESULT
178 getchr_va(PARROT_INTERP
, SHIM(INTVAL size
), ARGIN(SPRINTF_OBJ
*obj
))
180 ASSERT_ARGS(getchr_va
)
181 va_list *arg
= (va_list *)(obj
->data
);
183 /* char promoted to int */
184 char ch
= (char)va_arg(*arg
, int);
186 return string_make(interp
, &ch
, 1, "iso-8859-1", 0);
191 =item C<static HUGEINTVAL getint_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
194 Gets an integer out of the C<va_list> in C<obj> and returns it as a
197 C<size> is an C<enum spf_type_t> value which indicates the storage type
204 PARROT_WARN_UNUSED_RESULT
206 getint_va(PARROT_INTERP
, INTVAL size
, ARGIN(SPRINTF_OBJ
*obj
))
208 ASSERT_ARGS(getint_va
)
209 va_list * const arg
= (va_list *)(obj
->data
);
213 return va_arg(*arg
, int);
216 /* "'short int' is promoted to 'int' when passed through '...'" */
217 return (short)va_arg(*arg
, int);
220 return va_arg(*arg
, long);
223 return va_arg(*arg
, HUGEINTVAL
);
226 return va_arg(*arg
, INTVAL
);
229 return va_arg(*arg
, opcode_t
);
233 PMC
* const pmc
= (PMC
*)va_arg(*arg
, PMC
*);
234 return VTABLE_get_integer(interp
, pmc
);
238 PANIC(interp
, "Invalid int type!");
244 =item C<static UHUGEINTVAL getuint_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
247 Gets an unsigned integer out of the C<va_list> in C<obj> and returns it
248 as a Parrot C<STRING>.
250 C<size> is an C<enum spf_type_t> value which indicates the storage type
257 PARROT_WARN_UNUSED_RESULT
259 getuint_va(PARROT_INTERP
, INTVAL size
, ARGIN(SPRINTF_OBJ
*obj
))
261 ASSERT_ARGS(getuint_va
)
262 va_list * const arg
= (va_list *)(obj
->data
);
266 return va_arg(*arg
, unsigned int);
269 /* short int promoted HLAGHLAGHLAGH. See note above */
270 return (unsigned short)va_arg(*arg
, unsigned int);
273 return va_arg(*arg
, unsigned long);
276 return va_arg(*arg
, UHUGEINTVAL
);
279 return va_arg(*arg
, UINTVAL
);
282 return va_arg(*arg
, opcode_t
);
286 PMC
* const pmc
= va_arg(*arg
, PMC
*);
287 return (UINTVAL
)VTABLE_get_integer(interp
, pmc
);
291 PANIC(interp
, "Invalid uint type!");
297 =item C<static HUGEFLOATVAL getfloat_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
300 Gets an floating-point number out of the C<va_list> in C<obj> and
301 returns it as a Parrot C<STRING>.
303 C<size> is an C<enum spf_type_t> value which indicates the storage type of
310 PARROT_WARN_UNUSED_RESULT
312 getfloat_va(PARROT_INTERP
, INTVAL size
, ARGIN(SPRINTF_OBJ
*obj
))
314 ASSERT_ARGS(getfloat_va
)
315 va_list * const arg
= (va_list *)(obj
->data
);
319 /* float is promoted to double */
320 return (HUGEFLOATVAL
)(float)va_arg(*arg
, double);
323 return (HUGEFLOATVAL
)(double)va_arg(*arg
, double);
326 return (HUGEFLOATVAL
)(HUGEFLOATVAL
) va_arg(*arg
, HUGEFLOATVAL
);
329 return (HUGEFLOATVAL
)(FLOATVAL
) va_arg(*arg
, FLOATVAL
);
333 PMC
* const pmc
= (PMC
*)va_arg(*arg
, PMC
*);
335 return (HUGEFLOATVAL
)(VTABLE_get_number(interp
, pmc
));
339 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_CHARACTER
,
340 "Internal sprintf doesn't recognize size %d for a float", size
);
346 =item C<static STRING * getstring_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
349 Gets an string out of the C<va_list> in C<obj> and returns it as a
352 C<size> is an C<enum spf_type_t> value which indicates the storage type
359 PARROT_WARN_UNUSED_RESULT
360 PARROT_CANNOT_RETURN_NULL
362 getstring_va(PARROT_INTERP
, INTVAL size
, ARGIN(SPRINTF_OBJ
*obj
))
364 ASSERT_ARGS(getstring_va
)
365 va_list * const arg
= (va_list *)(obj
->data
);
370 const char * const cstr
= (char *)va_arg(*arg
, char *);
372 return cstr2pstr(cstr
);
377 STRING
* const s
= (STRING
*)va_arg(*arg
, STRING
*);
378 return s
? s
: CONST_STRING(interp
, "(null)");
384 PMC
* const pmc
= (PMC
*)va_arg(*arg
, PMC
*);
385 STRING
* const s
= VTABLE_get_string(interp
, pmc
);
391 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_CHARACTER
,
392 "Internal sprintf doesn't recognize size %d for a string", size
);
398 =item C<static void * getptr_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ *obj)>
400 Gets a C<void *> out of the C<va_list> in C<obj> and returns it.
408 PARROT_WARN_UNUSED_RESULT
409 PARROT_CAN_RETURN_NULL
411 getptr_va(SHIM_INTERP
, SHIM(INTVAL size
), ARGIN(SPRINTF_OBJ
*obj
))
413 ASSERT_ARGS(getptr_va
)
414 va_list * const arg
= (va_list *)(obj
->data
);
416 return (void *)va_arg(*arg
, void *);
419 const SPRINTF_OBJ va_core
= {
420 NULL
, 0, getchr_va
, getint_va
, getuint_va
,
421 getfloat_va
, getstring_va
, getptr_va
432 =item C<static STRING * getchr_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
435 Same as C<getchr_va()> except that a vtable is used to get the value
442 PARROT_CANNOT_RETURN_NULL
443 PARROT_WARN_UNUSED_RESULT
445 getchr_pmc(PARROT_INTERP
, SHIM(INTVAL size
), ARGMOD(SPRINTF_OBJ
*obj
))
447 ASSERT_ARGS(getchr_pmc
)
449 PMC
* const tmp
= VTABLE_get_pmc_keyed_int(interp
,
454 s
= VTABLE_get_string(interp
, tmp
);
455 /* XXX Parrot_str_copy like below? + adjusting bufused */
456 return Parrot_str_substr(interp
, s
, 0, 1, NULL
, 0);
461 =item C<static HUGEINTVAL getint_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
464 Same as C<getint_va()> except that a vtable is used to get the value
471 PARROT_WARN_UNUSED_RESULT
473 getint_pmc(PARROT_INTERP
, INTVAL size
, ARGIN(SPRINTF_OBJ
*obj
))
475 ASSERT_ARGS(getint_pmc
)
477 PMC
* const tmp
= VTABLE_get_pmc_keyed_int(interp
,
482 ret
= VTABLE_get_integer(interp
, tmp
);
488 /* case SIZE_REG: ret=(HUGEINTVAL)(int)ret; break; */
501 =item C<static UHUGEINTVAL getuint_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
504 Same as C<getuint_va()> except that a vtable is used to get the value
511 PARROT_WARN_UNUSED_RESULT
513 getuint_pmc(PARROT_INTERP
, INTVAL size
, ARGIN(SPRINTF_OBJ
*obj
))
515 ASSERT_ARGS(getuint_pmc
)
517 PMC
* const tmp
= VTABLE_get_pmc_keyed_int(interp
,
522 ret
= (UINTVAL
)VTABLE_get_integer(interp
, tmp
);
526 ret
= (unsigned short)ret
;
528 /* case SIZE_REG: * ret=(UHUGEINTVAL)(unsigned int)ret; * break; */
530 ret
= (unsigned long)ret
;
541 =item C<static HUGEFLOATVAL getfloat_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
544 Same as C<getfloat_va()> except that a vtable is used to get the value
551 PARROT_WARN_UNUSED_RESULT
553 getfloat_pmc(PARROT_INTERP
, INTVAL size
, ARGIN(SPRINTF_OBJ
*obj
))
555 ASSERT_ARGS(getfloat_pmc
)
557 PMC
* const tmp
= VTABLE_get_pmc_keyed_int(interp
,
562 ret
= (HUGEFLOATVAL
)(VTABLE_get_number(interp
, tmp
));
566 ret
= (HUGEFLOATVAL
)(float)ret
;
568 /* case SIZE_REG: * ret=(HUGEFLOATVAL)(double)ret; * break; */
578 =item C<static STRING * getstring_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
581 Same as C<getstring_va()> except that a vtable is used to get the value
588 PARROT_WARN_UNUSED_RESULT
589 PARROT_CANNOT_RETURN_NULL
591 getstring_pmc(PARROT_INTERP
, SHIM(INTVAL size
), ARGIN(SPRINTF_OBJ
*obj
))
593 ASSERT_ARGS(getstring_pmc
)
595 PMC
* const tmp
= VTABLE_get_pmc_keyed_int(interp
,
600 s
= (STRING
*)(VTABLE_get_string(interp
, tmp
));
606 =item C<static void * getptr_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ *obj)>
608 Same as C<getptr_va()> except that a vtable is used to get the value
615 PARROT_WARN_UNUSED_RESULT
616 PARROT_CANNOT_RETURN_NULL
618 getptr_pmc(PARROT_INTERP
, SHIM(INTVAL size
), ARGIN(SPRINTF_OBJ
*obj
))
620 ASSERT_ARGS(getptr_pmc
)
621 PMC
* const tmp
= VTABLE_get_pmc_keyed_int(interp
,
622 ((PMC
*)obj
->data
), (obj
->index
));
623 const INTVAL i
= VTABLE_get_integer(interp
, tmp
);
631 SPRINTF_OBJ pmc_core
= {
632 NULL
, 0, getchr_pmc
, getint_pmc
, getuint_pmc
,
633 getfloat_pmc
, getstring_pmc
, getptr_pmc
642 F<src/misc.h>, F<src/misc.c>, F<src/spf_render.c>.
646 When I was first working on this implementation of sprintf, I ran into a
647 problem. I wanted to re-use the implementation for a Parrot
648 bytecode-level sprintf, but that couldn't be done, since it used C<va_*>
649 directly. For a while I thought about generating two versions of the
650 source with a Perl script, but that seemed like overkill. Eventually I
651 came across this idea -- pass in a specialized vtable with methods for
652 extracting things from the arglist, whatever it happened to be. This is
657 In the future, it may be deemed desirable to similarly vtable-ize
658 appending things to the string, allowing for faster C<Parrot_io_printf()> &c,
659 as well as a version that writes directly to a C string. However, at
660 this point neither of those is needed.
669 * c-file-style: "parrot"
671 * vim: expandtab shiftwidth=4: