fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / spf_vtable.c
blob66b1ed6e5ec66a927b30b1bb0dab9e9f82168b12
1 /*
2 Copyright (C) 2001-2009, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/spf_vtable.c - Parrot sprintf
9 =head1 DESCRIPTION
11 Implements the two families of functions C<Parrot_sprintf> may use to
12 retrieve arguments.
14 =head2 Var args Functions
16 =over 4
18 =cut
22 #define IN_SPF_SYSTEM
24 #include "parrot/parrot.h"
26 #include <stdarg.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,
37 SHIM(INTVAL size),
38 ARGMOD(SPRINTF_OBJ *obj))
39 __attribute__nonnull__(1)
40 __attribute__nonnull__(3)
41 FUNC_MODIFIES(*obj);
43 PARROT_CANNOT_RETURN_NULL
44 PARROT_WARN_UNUSED_RESULT
45 static STRING * getchr_va(PARROT_INTERP,
46 SHIM(INTVAL size),
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,
53 INTVAL size,
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,
60 INTVAL size,
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,
67 INTVAL size,
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,
74 INTVAL size,
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,
82 SHIM(INTVAL size),
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,
90 SHIM(INTVAL size),
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,
97 SHIM(INTVAL size),
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,
105 INTVAL size,
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,
112 INTVAL size,
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,
119 INTVAL size,
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
167 Parrot C<STRING>.
169 C<size> is unused.
171 =cut
175 PARROT_CANNOT_RETURN_NULL
176 PARROT_WARN_UNUSED_RESULT
177 static STRING *
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 Parrot_str_new_init(interp, &ch, 1, Parrot_latin1_encoding_ptr, 0);
191 =item C<static HUGEINTVAL getint_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
192 *obj)>
194 Gets an integer out of the C<va_list> in C<obj> and returns it as a
195 Parrot C<STRING>.
197 C<size> is an C<enum spf_type_t> value which indicates the storage type
198 of the integer.
200 =cut
204 PARROT_WARN_UNUSED_RESULT
205 static HUGEINTVAL
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);
211 switch (size) {
212 case SIZE_REG:
213 return va_arg(*arg, int);
215 case SIZE_SHORT:
216 /* "'short int' is promoted to 'int' when passed through '...'" */
217 return (short)va_arg(*arg, int);
219 case SIZE_LONG:
220 return va_arg(*arg, long);
222 case SIZE_HUGE:
223 return va_arg(*arg, HUGEINTVAL);
225 case SIZE_XVAL:
226 return va_arg(*arg, INTVAL);
228 case SIZE_OPCODE:
229 return va_arg(*arg, opcode_t);
231 case SIZE_PMC:
233 PMC * const pmc = (PMC *)va_arg(*arg, PMC *);
234 return VTABLE_get_integer(interp, pmc);
237 default:
238 PANIC(interp, "Invalid int type!");
244 =item C<static UHUGEINTVAL getuint_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
245 *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
251 of the integer.
253 =cut
257 PARROT_WARN_UNUSED_RESULT
258 static UHUGEINTVAL
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);
264 switch (size) {
265 case SIZE_REG:
266 return va_arg(*arg, unsigned int);
268 case SIZE_SHORT:
269 /* short int promoted HLAGHLAGHLAGH. See note above */
270 return (unsigned short)va_arg(*arg, unsigned int);
272 case SIZE_LONG:
273 return va_arg(*arg, unsigned long);
275 case SIZE_HUGE:
276 return va_arg(*arg, UHUGEINTVAL);
278 case SIZE_XVAL:
279 return va_arg(*arg, UINTVAL);
281 case SIZE_OPCODE:
282 return va_arg(*arg, opcode_t);
284 case SIZE_PMC:
286 PMC * const pmc = va_arg(*arg, PMC *);
287 return (UINTVAL)VTABLE_get_integer(interp, pmc);
290 default:
291 PANIC(interp, "Invalid uint type!");
297 =item C<static HUGEFLOATVAL getfloat_va(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
298 *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
304 the number.
306 =cut
310 PARROT_WARN_UNUSED_RESULT
311 static HUGEFLOATVAL
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);
317 switch (size) {
318 case SIZE_SHORT:
319 /* float is promoted to double */
320 return (HUGEFLOATVAL)(float)va_arg(*arg, double);
322 case SIZE_REG:
323 return (HUGEFLOATVAL)(double)va_arg(*arg, double);
325 case SIZE_HUGE:
326 return (HUGEFLOATVAL)(HUGEFLOATVAL) va_arg(*arg, HUGEFLOATVAL);
328 case SIZE_XVAL:
329 return (HUGEFLOATVAL)(FLOATVAL) va_arg(*arg, FLOATVAL);
331 case SIZE_PMC:
333 PMC * const pmc = (PMC *)va_arg(*arg, PMC *);
335 return (HUGEFLOATVAL)(VTABLE_get_number(interp, pmc));
338 default:
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
347 *obj)>
349 Gets an string out of the C<va_list> in C<obj> and returns it as a
350 Parrot C<STRING>.
352 C<size> is an C<enum spf_type_t> value which indicates the storage type
353 of the string.
355 =cut
359 PARROT_WARN_UNUSED_RESULT
360 PARROT_CANNOT_RETURN_NULL
361 static STRING *
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);
367 switch (size) {
368 case SIZE_REG:
370 const char * const cstr = (char *)va_arg(*arg, char *);
372 return cstr2pstr(cstr);
375 case SIZE_PSTR:
377 STRING * const s = (STRING *)va_arg(*arg, STRING *);
378 return s ? s : CONST_STRING(interp, "(null)");
382 case SIZE_PMC:
384 PMC * const pmc = (PMC *)va_arg(*arg, PMC *);
385 STRING * const s = VTABLE_get_string(interp, pmc);
387 return s;
390 default:
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.
402 C<size> is unused.
404 =cut
408 PARROT_WARN_UNUSED_RESULT
409 PARROT_CAN_RETURN_NULL
410 static void *
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
426 =back
428 =head2 PMC Functions
430 =over 4
432 =item C<static STRING * getchr_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
433 *obj)>
435 Same as C<getchr_va()> except that a vtable is used to get the value
436 from C<obj>.
438 =cut
442 PARROT_CANNOT_RETURN_NULL
443 PARROT_WARN_UNUSED_RESULT
444 static STRING *
445 getchr_pmc(PARROT_INTERP, SHIM(INTVAL size), ARGMOD(SPRINTF_OBJ *obj))
447 ASSERT_ARGS(getchr_pmc)
448 STRING *s;
449 PMC * const tmp = VTABLE_get_pmc_keyed_int(interp,
450 ((PMC *)obj->data),
451 (obj->index));
453 ++obj->index;
454 s = VTABLE_get_string(interp, tmp);
455 return Parrot_str_substr(interp, s, 0, 1);
460 =item C<static HUGEINTVAL getint_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
461 *obj)>
463 Same as C<getint_va()> except that a vtable is used to get the value
464 from C<obj>.
466 =cut
470 PARROT_WARN_UNUSED_RESULT
471 static HUGEINTVAL
472 getint_pmc(PARROT_INTERP, INTVAL size, ARGIN(SPRINTF_OBJ *obj))
474 ASSERT_ARGS(getint_pmc)
476 PMC * const tmp = VTABLE_get_pmc_keyed_int(interp,
477 ((PMC *)obj->data),
478 (obj->index++));
480 HUGEINTVAL ret = VTABLE_get_integer(interp, tmp);
482 switch (size) {
483 case SIZE_SHORT:
484 ret = (short)ret;
485 break;
486 /* case SIZE_REG: ret=(HUGEINTVAL)(int)ret; break; */
487 case SIZE_LONG:
488 ret = (long)ret;
489 break;
490 default:
491 /* nothing */ ;
494 return ret;
499 =item C<static UHUGEINTVAL getuint_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
500 *obj)>
502 Same as C<getuint_va()> except that a vtable is used to get the value
503 from C<obj>.
505 =cut
509 PARROT_WARN_UNUSED_RESULT
510 static UHUGEINTVAL
511 getuint_pmc(PARROT_INTERP, INTVAL size, ARGIN(SPRINTF_OBJ *obj))
513 ASSERT_ARGS(getuint_pmc)
515 PMC * const tmp = VTABLE_get_pmc_keyed_int(interp,
516 ((PMC *)obj->data),
517 (obj->index++));
519 UHUGEINTVAL ret = (UINTVAL)VTABLE_get_integer(interp, tmp);
521 switch (size) {
522 case SIZE_SHORT:
523 ret = (unsigned short)ret;
524 break;
525 /* case SIZE_REG: * ret=(UHUGEINTVAL)(unsigned int)ret; * break; */
526 case SIZE_LONG:
527 ret = (unsigned long)ret;
528 break;
529 default:
530 /* nothing */ ;
533 return ret;
538 =item C<static HUGEFLOATVAL getfloat_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
539 *obj)>
541 Same as C<getfloat_va()> except that a vtable is used to get the value
542 from C<obj>.
544 =cut
548 PARROT_WARN_UNUSED_RESULT
549 static HUGEFLOATVAL
550 getfloat_pmc(PARROT_INTERP, INTVAL size, ARGIN(SPRINTF_OBJ *obj))
552 ASSERT_ARGS(getfloat_pmc)
553 PMC * const tmp = VTABLE_get_pmc_keyed_int(interp,
554 ((PMC *)obj->data),
555 (obj->index++));
557 HUGEFLOATVAL ret = (HUGEFLOATVAL)(VTABLE_get_number(interp, tmp));
559 switch (size) {
560 case SIZE_SHORT:
561 ret = (HUGEFLOATVAL)(float)ret;
562 break;
563 /* case SIZE_REG: * ret=(HUGEFLOATVAL)(double)ret; * break; */
564 default:
565 /* nothing */ ;
568 return ret;
573 =item C<static STRING * getstring_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ
574 *obj)>
576 Same as C<getstring_va()> except that a vtable is used to get the value
577 from C<obj>.
579 =cut
583 PARROT_WARN_UNUSED_RESULT
584 PARROT_CANNOT_RETURN_NULL
585 static STRING *
586 getstring_pmc(PARROT_INTERP, SHIM(INTVAL size), ARGIN(SPRINTF_OBJ *obj))
588 ASSERT_ARGS(getstring_pmc)
590 PMC * const tmp = VTABLE_get_pmc_keyed_int(interp,
591 ((PMC *)obj->data),
592 (obj->index++));
594 STRING * const str = (STRING *)(VTABLE_get_string(interp, tmp));
595 return str;
600 =item C<static void * getptr_pmc(PARROT_INTERP, INTVAL size, SPRINTF_OBJ *obj)>
602 Same as C<getptr_va()> except that a vtable is used to get the value
603 from C<obj>.
605 =cut
609 PARROT_WARN_UNUSED_RESULT
610 PARROT_CANNOT_RETURN_NULL
611 static void *
612 getptr_pmc(PARROT_INTERP, SHIM(INTVAL size), ARGIN(SPRINTF_OBJ *obj))
614 ASSERT_ARGS(getptr_pmc)
615 PMC * const tmp = VTABLE_get_pmc_keyed_int(interp,
616 ((PMC *)obj->data), (obj->index++));
617 const INTVAL i = VTABLE_get_integer(interp, tmp);
619 /* XXX correct? */
620 return (void *)i;
623 SPRINTF_OBJ pmc_core = {
624 NULL, 0, getchr_pmc, getint_pmc, getuint_pmc,
625 getfloat_pmc, getstring_pmc, getptr_pmc
630 =back
632 =head1 SEE ALSO
634 F<src/misc.h>, F<src/misc.c>, F<src/spf_render.c>.
636 =head1 HISTORY
638 When I was first working on this implementation of sprintf, I ran into a
639 problem. I wanted to re-use the implementation for a Parrot
640 bytecode-level sprintf, but that couldn't be done, since it used C<va_*>
641 directly. For a while I thought about generating two versions of the
642 source with a Perl script, but that seemed like overkill. Eventually I
643 came across this idea -- pass in a specialized vtable with methods for
644 extracting things from the arglist, whatever it happened to be. This is
645 the result.
647 =head1 TODO
649 In the future, it may be deemed desirable to similarly vtable-ize
650 appending things to the string, allowing for faster C<Parrot_io_printf()> &c,
651 as well as a version that writes directly to a C string. However, at
652 this point neither of those is needed.
654 =cut
660 * Local variables:
661 * c-file-style: "parrot"
662 * End:
663 * vim: expandtab shiftwidth=4: