File Coverage

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