File Coverage

XS.xs
Criterion Covered Total %
statement 48 52 92.3
branch 39 44 88.6
condition n/a
subroutine n/a
pod n/a
total 87 96 90.6


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "ppport.h"
6             #include
7             #include
8             #include "words.h"
9              
10             #ifndef __bool_true_false_are_defined
11             # define __bool_true_false_are_defined 1
12             # define false 0
13             # define true 1
14             #endif
15              
16             #ifndef U64
17             typedef uint64_t U64;
18             #endif
19              
20             #ifndef likely
21             # define likely(x) __builtin_expect((x), 1)
22             #endif
23              
24             #ifndef unlikely
25             # define unlikely(x) __builtin_expect((x), 0)
26             #endif
27              
28             /* Macro for choosing the ending corresponding to the specified value */
29             #define ending4value(value) \
30             ((value) % 100 / 10 - 1) && (value) % 10 > 0 && (value) % 10 < 5 \
31             ? (value) % 10 > 1 ? COUPLE : SINGLE : SEVERAL
32              
33             #define double2kopeck(value) \
34             (U8) nearbyint(((value) - (U64) (value)) * 100) % 100
35              
36             STATIC SV *
37 5099           kopeck2words(pTHX_ U8 value, bool words) {
38 5099 100         U8 ending = ending4value(value);
    100          
    100          
39 5099           SV *value_pv = sv_2mortal(newSVpvs(""));
40 5099 100         if (words) {
41 2 50         if (value % 100 < 20) {
42 2 50         const char *word = strcmp(funits[value % 100], "") ? funits[value % 100] : zero;
43 2           sv_catpvn(value_pv, word, strlen(word));
44             } else {
45 0           sv_catpvn(value_pv, tens[value % 100 / 10], strlen(tens[value % 100 / 10]));
46 0           sv_catpvn(value_pv, funits[value % 10], strlen(funits[value % 10]));
47             }
48             } else {
49             char value_str[4];
50 10194           sprintf(value_str, "%02d ", value);
51 5097           sv_catpvn(value_pv, value_str, strlen(value_str));
52             }
53 5099           sv_catpvn(value_pv, kopeck[ending], strlen(kopeck[ending]));
54 5099           return value_pv;
55             }
56              
57             STATIC SV *
58 15005           ruble2words(pTHX_ U16 value, U8 decade, bool words) {
59 15005 100         U8 ending = ending4value(value);
    100          
    100          
60 15005           SV *value_pv = sv_2mortal(newSVpvs(""));
61 15005 100         if (!value) {
62 9990 100         if (!decade)
63 3996           sv_catpvn(value_pv, ruble[decade][ending], strlen(ruble[decade][ending]));
64             return value_pv;
65             }
66 5015 50         if (words) {
67 5015           sv_catpvn(value_pv, hundreds[value / 100], strlen(hundreds[value / 100]));
68 5015 100         char **units = (char **) (decade == THOUSAND ? funits : munits);
69 5015 100         if (value % 100 < 20) {
70 997           sv_catpvn(value_pv, units[value % 100], strlen(units[value % 100]));
71             } else {
72 4018           sv_catpvn(value_pv, tens[value % 100 / 10], strlen(tens[value % 100 / 10]));
73 4018           sv_catpvn(value_pv, units[value % 10], strlen(units[value % 10]));
74             }
75             } else {
76             char value_str[5];
77 0           sprintf(value_str, "%d ", value);
78 0           sv_catpvn(value_pv, value_str, strlen(value_str));
79             }
80 5015           sv_catpvn(value_pv, ruble[decade][ending], strlen(ruble[decade][ending]));
81 5015           return value_pv;
82             }
83              
84             STATIC SV *
85 5101           money2words(pTHX_ double amount, bool ruble_cvt, bool kopeck_cvt) {
86 5101 100         if (unlikely(amount < MONEY_MIN))
87 1           croak("Negative amount can't be processed");
88 5100 100         if (unlikely(amount >= MONEY_MAX))
89 1           croak("Given amount can't be processed due to the type overflow");
90 5099 100         if (unlikely(amount >= pow(1e3, TRILLION)))
91 1003           warn("Kopeck value is calculated inaccurate due to the lack for "
92             "significant digits after the radix point");
93 5099 100         U8 kopeck_v = amount < pow(1e3, TRILLION) ? double2kopeck(amount) : 0;
94 5099           AV *stack = (AV *) sv_2mortal((SV *) newAV());
95 5099           av_push(stack, kopeck2words(aTHX_ kopeck_v, kopeck_cvt));
96 5099           U64 ruble_v = (U64) amount;
97             U8 decade;
98 20104 100         for (decade = UNIT; ruble_v > 0; ruble_v /= 1000, decade++)
99 15005           av_push(stack, ruble2words(aTHX_ ruble_v % 1000, decade, ruble_cvt));
100             /* Build the result string */
101 5099           SV *words = sv_2mortal(newSVpvs(""));
102 25203 100         while (av_len(stack) + 1)
103 20104           sv_catsv(words, av_pop(stack));
104 5099           SvUTF8_on(words);
105 5099           return words;
106             }
107              
108             MODULE = Lingua::RU::Money::XS PACKAGE = Lingua::RU::Money::XS
109              
110             void
111             rur2words(SV *amount)
112             PROTOTYPE: $
113             PPCODE:
114 5099 50         ST(0) = money2words(aTHX_ SvNV(amount), true, false);
115 5097           XSRETURN(1);
116              
117             void
118             all2words(SV *amount)
119             PROTOTYPE: $
120             PPCODE:
121 2 50         ST(0) = money2words(aTHX_ SvNV(amount), true, true);
122 2           XSRETURN(1);