File Coverage

LUHN_XS.xs
Criterion Covered Total %
statement 114 114 100.0
branch 49 50 98.0
condition n/a
subroutine n/a
pod n/a
total 163 164 99.3


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5              
6              
7             #include
8             #include
9             int _al_vc[256];
10             #define MAX_ERROR_LEN 200
11              
12             /* you may be asking...why? */
13             /* well, windows and older versions of MacOS don't have strndup, so... */
14 52           char * _al_substr(const char* src, const int offset, const int len) {
15 52           char * sub = (char*)malloc(len+1);
16 52           memcpy(sub, src + offset, len);
17 52           sub[len] = 0;
18 52           return sub;
19             }
20              
21             /* needed for Devel::Cover */
22 1           void _al_test_croak() {
23 1           S_croak_memory_wrap();
24             }
25              
26             /* not thread safe, don't use this module with perl threads */
27 11           int _al_init_vc(SV* hash_ref) {
28             HV* hash;
29             HE* hash_entry;
30             int num_keys, i;
31             SV* sv_key;
32             SV* sv_val;
33 2827 100         for (i=0;i<256;++i) {
34 2816           _al_vc[i]=-1;
35             }
36 11           hash = (HV*)SvRV(hash_ref);
37 11           num_keys = hv_iterinit(hash);
38 445 100         for (i = 0; i < num_keys; i++) {
39 434           hash_entry = hv_iternext(hash);
40 434           sv_key = hv_iterkeysv(hash_entry);
41 434           sv_val = hv_iterval(hash, hash_entry);
42 434 50         _al_vc[(SvPV(sv_key,PL_na))[0]]=atoi(SvPV(sv_val,PL_na)); /* #uncoverable statment */
    100          
43             }
44 11           return 1;
45             }
46              
47 19           int check_digit_rff(char *input) {
48 19           int len=strlen(input)-1;
49 19 100         if (len < 1) {
50 2           return -1;
51             }
52             static int deltas[]={ 0, 1, 2, 3, 4, -4, -3, -2, -1, 0 };
53 17           int checksum=0;
54 17           int flip=0;
55             int i,j;
56 161 100         for (i = len; i >=0; --i) {
57 149           j=input[i]-48;
58             /* only handle numeric input */
59 149 100         if (j > 9 || j < 0) {return -1;}
    100          
60 144           checksum += j;
61 144 100         if (flip ^= 1) {
62 75           checksum += deltas[j];
63             }
64             }
65 12           checksum *= 9;
66 12           return(checksum%10);
67             }
68              
69 70           int check_digit_fast(char *input) {
70             int i, sum, ch, num, twoup, len;
71 70           len = strlen(input);
72 70 100         if (len < 1) {
73             char err[MAX_ERROR_LEN];
74 2           snprintf(err,MAX_ERROR_LEN,"check_digit_fast: No input string.");
75             SV *error;
76 2           error=get_sv("Algorithm::LUHN_XS::ERROR",GV_ADD);
77 2           sv_setpv(error,err);
78 2           return -1;
79             }
80 68           sum = 0;
81 68           twoup = 1;
82 700 100         for (i = len - 1; i >= 0; --i) {
83 640           num=_al_vc[input[i]];
84 640 100         if (num == -1) {
85             /* Don't change the error text, perl tests depend on the exact words */
86             char err[MAX_ERROR_LEN];
87 8           snprintf(err,MAX_ERROR_LEN,"Invalid character '%c', in check_digit calculation",input[i]);
88             SV *error;
89 8           error=get_sv("Algorithm::LUHN_XS::ERROR",GV_ADD);
90 8           sv_setpv(error,err);
91 8           return -1;
92             }
93 632 100         if (!(twoup = !twoup)) {
94 326           num *= 2;
95             }
96 1408 100         while (num) {
97 776           sum += num % 10;
98 776           num=num/10;
99             }
100             }
101 60           return((10-(sum %10)) % 10);
102             }
103              
104 15           SV* check_digit(char *input) {
105 15           int len=strlen(input);
106 15 100         if (len < 1) {
107 2           return &PL_sv_undef;
108             }
109 13           int rv=check_digit_fast(input);
110 13 100         if (rv == -1) {
111 3           return &PL_sv_undef;
112             } else {
113 10           return newSViv(rv);
114             }
115             }
116              
117 24           SV* is_valid(char *input) {
118 24           int len=strlen(input);
119 24 100         if (len < 2) {
120             char err[MAX_ERROR_LEN];
121 3           snprintf(err,MAX_ERROR_LEN,
122             "is_valid: you must supply input of at least 2 characters");
123             SV *error;
124 3           error=get_sv("Algorithm::LUHN_XS::ERROR",GV_ADD);
125 3           sv_setpv(error,err);
126 3           SV* rv=newSVpv(NULL,1);
127 3           return rv;
128             }
129 21           char *leftmost=_al_substr(input,0,len-1);
130 21           char cd=input[len-1];
131 21           char c=check_digit_fast(leftmost)+'0';
132 21           free(leftmost);
133 21 100         if (c < 48) {
134 1           SV* rv=newSVpv(NULL,1);
135 1           return rv;
136             } else {
137 20 100         if (cd == c) {
138 10           return(newSViv(1));
139             } else {
140             char err[MAX_ERROR_LEN];
141 10           snprintf(err,MAX_ERROR_LEN,
142             "Check digit incorrect. Expected %c",c);
143             SV *error;
144 10           error=get_sv("Algorithm::LUHN_XS::ERROR",GV_ADD);
145 10           sv_setpv(error,err);
146 10           SV* rv=newSVpv(NULL,1);
147 10           return rv;
148             }
149             }
150             }
151              
152 24           int is_valid_fast(char *input) {
153 24           int len=strlen(input);
154 24 100         if (len < 2) {
155 3           return 0;
156             }
157 21           char *leftmost=_al_substr(input,0,len-1);
158 21           char cd=input[len-1];
159 21           char c=check_digit_fast(leftmost)+'0';
160 21           free(leftmost);
161              
162 21 100         if (c < 48) {
163 1           return 0;
164             } else {
165 20 100         if (cd == c) {
166 10           return 1;
167             } else {
168             char err[MAX_ERROR_LEN];
169 10           snprintf(err,MAX_ERROR_LEN,
170             "Check digit incorrect. Expected %c",c);
171             SV *error;
172 10           error=get_sv("Algorithm::LUHN_XS::ERROR",GV_ADD);
173 10           sv_setpv(error,err);
174 10           return 0;
175             }
176             }
177             }
178              
179 13           int is_valid_rff(char *input) {
180             char csum;
181 13           int len=strlen(input);
182 13 100         if (len < 2) {
183 3           return 0;
184             }
185 10           char cd=input[len-1];
186 10           char *leftmost=_al_substr(input,0,len-1);
187 10           int d=check_digit_rff(leftmost);
188 10           csum=d+'0';
189 10           free(leftmost);
190 10 100         if (csum < 48) {
191 2           return 0;
192             } else {
193 8 100         if (cd == csum) {
194 4           return 1;
195             } else {
196 4           return 0;
197             }
198             }
199             }
200              
201             MODULE = Algorithm::LUHN_XS PACKAGE = Algorithm::LUHN_XS
202              
203             PROTOTYPES: DISABLE
204              
205              
206             int
207             _al_init_vc (hash_ref)
208             SV * hash_ref
209              
210             int
211             check_digit_rff (input)
212             char * input
213              
214             int
215             check_digit_fast (input)
216             char * input
217              
218             SV*
219             check_digit(input)
220             char * input
221              
222             SV*
223             is_valid(input)
224             char * input
225              
226             int
227             is_valid_fast(input)
228             char * input
229              
230             int
231             is_valid_rff(input)
232             char * input
233              
234             void
235             _al_test_croak()