File Coverage

lib/Lingua/Stem/Snowball/Ca.xs
Criterion Covered Total %
statement 60 80 75.0
branch 31 70 44.2
condition n/a
subroutine n/a
pod n/a
total 91 150 60.6


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #define NEED_sv_2pv_flags
6             #define NEED_sv_2pv_nolen
7             #include "../ppport.h"
8              
9             #define NUMLANG 1
10             #define NUMSTEM 1
11              
12             #include "include/libstemmer.h"
13              
14             /* All Lingua::Stem::Snowball::Ca objects and all calls to stem(),
15             * stem_in_place(), etc, reference the same set of Snowball struct
16             * sb_stemmers, all held in the singleton object
17             * $Lingua::Stem::Snowball::Ca::stemmifier, of class
18             * Lingua::Stem::Snowball::Ca::Stemmifier. Each sb_stemmer is created lazily, as
19             * soon as there is a need for its unique combination of language and
20             * encoding. They are destroyed during global cleanup, when
21             * $Lingua::Stem::Snowball::Ca::stemmifier is reclaimed.
22             */
23              
24             typedef struct Stemmifier {
25             struct sb_stemmer **stemmers;
26             } Stemmifier;
27              
28             typedef struct LangEnc {
29             char *lang;
30             char *encoding; /* the real name of the encoding */
31             char *snowenc; /* the variant that libstemmer_c needs */
32             } LangEnc;
33              
34             LangEnc lang_encs[] = {
35             { "ca", "UTF-8", "UTF_8" },
36             };
37              
38             MODULE = Lingua::Stem::Snowball::Ca PACKAGE = Lingua::Stem::Snowball::Ca
39              
40             PROTOTYPES: disable
41              
42             BOOT:
43             {
44 3           SV *sb_stemmer_list_sv = newSViv(PTR2IV(sb_stemmer_list));
45 3           SV *sb_stemmer_new_sv = newSViv(PTR2IV(sb_stemmer_new));
46 3           SV *sb_stemmer_delete_sv = newSViv(PTR2IV(sb_stemmer_delete));
47 3           SV *sb_stemmer_stem_sv = newSViv(PTR2IV(sb_stemmer_stem));
48 3           SV *sb_stemmer_length_sv = newSViv(PTR2IV(sb_stemmer_length));
49 3           hv_store(PL_modglobal, "Lingua::Stem::Snowball::Ca::sb_stemmer_list", 39,
50             sb_stemmer_list_sv, 0);
51 3           hv_store(PL_modglobal, "Lingua::Stem::Snowball::Ca::sb_stemmer_new", 38,
52             sb_stemmer_new_sv, 0);
53 3           hv_store(PL_modglobal, "Lingua::Stem::Snowball::Ca::sb_stemmer_delete", 41,
54             sb_stemmer_delete_sv, 0);
55 3           hv_store(PL_modglobal, "Lingua::Stem::Snowball::Ca::sb_stemmer_stem", 39,
56             sb_stemmer_stem_sv, 0);
57 3           hv_store(PL_modglobal, "Lingua::Stem::Snowball::Ca::sb_stemmer_length", 41,
58             sb_stemmer_length_sv, 0);
59             }
60              
61             void
62             _derive_stemmer(self_hash)
63             HV *self_hash;
64             PPCODE:
65             {
66             SV **sv_ptr;
67             char *lang;
68             char *encoding;
69             int i;
70             int stemmer_id = -1;
71              
72             /* Extract lang and encoding member variables. */
73 7           sv_ptr = hv_fetch(self_hash, "lang", 4, 0);
74 7 50         if (!sv_ptr)
75 0           croak("Couldn't find member variable 'lang'");
76 7 50         lang = SvPV_nolen(*sv_ptr);
77 7           sv_ptr = hv_fetch(self_hash, "encoding", 8, 0);
78 7 50         if (!sv_ptr)
79 0           croak("Couldn't find member variable 'encoding'");
80 7 50         encoding = SvPV_nolen(*sv_ptr);
81              
82             /* See if the combo of lang and encoding is supported. */
83 7 50         for(i = 0; i < NUMSTEM; i++) {
84 7 50         if ( strcmp(lang, lang_encs[i].lang) == 0
85 7 50         && strcmp(encoding, lang_encs[i].encoding) == 0
86             ) {
87             Stemmifier *stemmifier;
88             SV *stemmifier_sv;
89              
90             /* We have a match, so we know the stemmer id now. */
91             stemmer_id = i;
92              
93             /* Retrieve communal Stemmifier. */
94 7           stemmifier_sv = get_sv("Lingua::Stem::Snowball::Ca::stemmifier", TRUE);
95 7 50         if ( sv_isobject(stemmifier_sv)
96 7 50         && sv_derived_from(stemmifier_sv,
97             "Lingua::Stem::Snowball::Ca::Stemmifier")
98             ) {
99 7 50         IV tmp = SvIV(SvRV(stemmifier_sv));
100 7           stemmifier = INT2PTR(Stemmifier*, tmp);
101             }
102             else {
103 0           croak("$L::S::S::stemmifier isn't a Stemmifier");
104             }
105              
106             /* Construct a stemmer for lang/enc if there isn't one yet. */
107 7 100         if ( ! stemmifier->stemmers[stemmer_id] ) {
108             stemmifier->stemmers[stemmer_id]
109 2           = sb_stemmer_new(lang, lang_encs[stemmer_id].snowenc);
110 2 50         if ( ! stemmifier->stemmers[stemmer_id] ) {
111 0           croak("Failed to allocate an sb_stemmer for %s %s", lang,
112             encoding);
113             }
114             }
115              
116             break;
117             }
118             }
119              
120             /* Set the value of $self->{stemmer_id}. */
121 7           sv_ptr = hv_fetch(self_hash, "stemmer_id", 10, 0);
122 7 50         if (!sv_ptr)
123 0           croak("Couldn't access $self->{stemmer_id}");
124 7           sv_setiv(*sv_ptr, stemmer_id);
125             }
126              
127             bool
128             _validate_language(language)
129             char *language;
130             CODE:
131             {
132             int i;
133             RETVAL = FALSE;
134 0 0         for (i = 0; i < NUMLANG; i++) {
135 0 0         if ( strcmp(language, lang_encs[i].lang) == 0 ) RETVAL = TRUE;
136             }
137             }
138             OUTPUT: RETVAL
139              
140             void
141             stem_in_place(self_hash, words_av)
142             HV *self_hash;
143             AV *words_av;
144             PPCODE:
145             {
146             IV stemmer_id;
147             SV **sv_ptr;
148             Stemmifier *stemmifier;
149             SV *stemmifier_sv;
150            
151             /* Retrieve the stemmifier. */
152 12           stemmifier_sv = get_sv("Lingua::Stem::Snowball::Ca::stemmifier", TRUE);
153 12 50         if ( sv_isobject(stemmifier_sv)
154 12 50         && sv_derived_from(stemmifier_sv, "Lingua::Stem::Snowball::Ca::Stemmifier")
155             ) {
156 12 50         IV tmp = SvIV(SvRV(stemmifier_sv));
157 12           stemmifier = INT2PTR(Stemmifier*, tmp);
158             }
159             else {
160 0           croak("$Lingua::Stem::Snowball::Ca::stemmifier isn't a Stemmifier");
161             }
162              
163             /* Figure out which sb_stemmer to use. */
164 12           sv_ptr = hv_fetch(self_hash, "stemmer_id", 10, 0);
165 12 50         if (!sv_ptr)
166 0           croak("Couldn't access stemmer_id");
167 12 50         stemmer_id = SvIV(*sv_ptr);
168 12 50         if ( stemmer_id < 0
169             || stemmer_id >= NUMSTEM
170 12 50         || stemmifier->stemmers[stemmer_id] == NULL
171             ) {
172 0           dSP;
173 0           ENTER;
174 0           SAVETMPS;
175 0 0         PUSHMARK(SP);
176 0 0         XPUSHs(ST(0));
177 0           PUTBACK;
178 0           call_method("_derive_stemmer", G_DISCARD);
179 0 0         FREETMPS;
180 0           LEAVE;
181            
182             /* Extract what should now be a valid stemmer_id. */
183 0           sv_ptr = hv_fetch(self_hash, "stemmer_id", 10, 0);
184 0 0         stemmer_id = SvIV(*sv_ptr);
185             }
186 12 50         if (stemmer_id != -1) {
187 12           struct sb_stemmer *stemmer = stemmifier->stemmers[stemmer_id];
188             IV i, max;
189              
190 28 100         for (i = 0, max = av_len(words_av); i <= max; i++) {
191 16           sv_ptr = av_fetch(words_av, i, 0);
192 16 50         if (SvOK(*sv_ptr)) {
    0          
    0          
193             STRLEN len;
194 16 50         sb_symbol *input_text = (sb_symbol*)SvPV(*sv_ptr, len);
195 16           const sb_symbol *stemmed_output
196 16           = sb_stemmer_stem(stemmer, input_text, (int)len);
197 16           len = sb_stemmer_length(stemmer);
198 16           sv_setpvn(*sv_ptr, (char*)stemmed_output, len);
199             }
200             }
201             }
202             }
203              
204             MODULE = Lingua::Stem::Snowball::Ca PACKAGE = Lingua::Stem::Snowball::Ca::Stemmifier
205              
206             SV*
207             new(class_name)
208             char* class_name;
209             CODE:
210             {
211             Stemmifier *stemmifier;
212 3           New(0, stemmifier, 1, Stemmifier);
213 3           Newz(0, stemmifier->stemmers, NUMSTEM, struct sb_stemmer*);
214 3           RETVAL = newSV(0);
215 3           sv_setref_pv(RETVAL, class_name, (void*)stemmifier);
216             }
217             OUTPUT: RETVAL
218              
219             void
220             DESTROY(self_sv)
221             SV *self_sv;
222             PPCODE:
223             {
224             int i;
225 3 50         IV temp = SvIV( SvRV(self_sv) );
226 3           Stemmifier *stemmifier = INT2PTR(Stemmifier*, temp);
227 6 100         for (i = 0; i < NUMSTEM; i++) {
228 3 100         if (stemmifier->stemmers[i] != NULL)
229 2           sb_stemmer_delete(stemmifier->stemmers[i]);
230             }
231 3           Safefree(stemmifier);
232             }
233