File Coverage

FASTX.xs
Criterion Covered Total %
statement 51 61 83.6
branch 83 166 50.0
condition n/a
subroutine n/a
pod n/a
total 134 227 59.0


line stmt bran cond sub pod time code
1             /* FASTA/FASTQ parser using kseq.h */
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include
7             #include "kseq.h"
8              
9             // Initialize kseq
10 36 100         KSEQ_INIT(gzFile, gzread)
  5 50          
  1 50          
  1 0          
  5 50          
  17 100          
  5 50          
  1 100          
  1 50          
    100          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
    50          
    100          
    50          
    0          
    0          
    100          
    50          
    50          
    0          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    100          
    50          
    100          
    100          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    0          
    100          
    100          
    50          
    50          
11              
12             // Helper function to convert a kseq_t record to a Perl hash reference
13 2           static SV* kseq_to_hash(pTHX_ kseq_t *seq) {
14 2           HV* hash = newHV();
15            
16             // Add name, always present
17 2           hv_store(hash, "name", 4, newSVpvn(seq->name.s, seq->name.l), 0);
18            
19             // Add sequence, always present
20 2           hv_store(hash, "seq", 3, newSVpvn(seq->seq.s, seq->seq.l), 0);
21            
22             // Add comment if present
23 2 50         if (seq->comment.l)
24 2           hv_store(hash, "comment", 7, newSVpvn(seq->comment.s, seq->comment.l), 0);
25            
26             // Add quality if present
27 2 50         if (seq->qual.l)
28 0           hv_store(hash, "qual", 4, newSVpvn(seq->qual.s, seq->qual.l), 0);
29            
30 2           return newRV_noinc((SV*)hash);
31             }
32              
33             MODULE = FASTX::XS PACKAGE = FASTX::XS
34             PROTOTYPES: DISABLE
35              
36             SV*
37             _xs_new(class, filename)
38             char* class
39             char* filename
40             CODE:
41             gzFile fp;
42             kseq_t *seq;
43            
44             // Open the file
45 1           fp = gzopen(filename, "r");
46 1 50         if (fp == NULL)
47 0           croak("Failed to open file: %s", filename);
48            
49             // Initialize kseq
50 1           seq = kseq_init(fp);
51 1 50         if (seq == NULL) {
52 0           gzclose(fp);
53 0           croak("Failed to initialize sequence parser");
54             }
55            
56             // Create a hash to store our object data
57 1           HV* self = newHV();
58            
59             // Store the file pointer and seq object as an IV
60 1           hv_store(self, "_fp", 3, newSViv(PTR2IV(fp)), 0);
61 1           hv_store(self, "_seq", 4, newSViv(PTR2IV(seq)), 0);
62            
63             // Bless and return
64 1           RETVAL = sv_bless(newRV_noinc((SV*)self), gv_stashpv(class, 0));
65             OUTPUT:
66             RETVAL
67              
68             SV*
69             next_seq(self)
70             SV* self
71             CODE:
72             HV* hash;
73             SV** fp_sv;
74             SV** seq_sv;
75             gzFile fp;
76             kseq_t *seq;
77             int ret;
78            
79             // Get the hash
80 3 50         if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
    50          
81 0           croak("Not a blessed hash reference");
82 3           hash = (HV*)SvRV(self);
83            
84             // Get the file pointer and seq object
85 3           fp_sv = hv_fetch(hash, "_fp", 3, 0);
86 3           seq_sv = hv_fetch(hash, "_seq", 4, 0);
87            
88 3 50         if (!fp_sv || !seq_sv)
    50          
89 0           croak("Invalid object");
90            
91             // Check if pointers are valid (not already freed)
92 3 50         if (!SvOK(*fp_sv) || SvIV(*fp_sv) == 0)
    50          
93 0           croak("File pointer has been freed");
94 3 50         if (!SvOK(*seq_sv) || SvIV(*seq_sv) == 0)
    50          
95 0           croak("Sequence parser has been freed");
96            
97 3           fp = INT2PTR(gzFile, SvIV(*fp_sv));
98 3           seq = INT2PTR(kseq_t*, SvIV(*seq_sv));
99            
100             // Read next sequence
101 3           ret = kseq_read(seq);
102            
103 3 100         if (ret < 0) {
104             // EOF or error
105 1           RETVAL = &PL_sv_undef;
106             } else {
107             // Convert to hash and return
108 2           RETVAL = kseq_to_hash(aTHX_ seq);
109             }
110             OUTPUT:
111             RETVAL
112              
113             void
114             DESTROY(self)
115             SV* self
116             CODE:
117             HV* hash;
118             SV** fp_sv;
119             SV** seq_sv;
120             gzFile fp;
121             kseq_t *seq;
122            
123             // Get the hash
124 1 50         if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
    50          
125 0           return;
126 1           hash = (HV*)SvRV(self);
127            
128             // Get the file pointer and seq object
129 1           fp_sv = hv_fetch(hash, "_fp", 3, 0);
130 1           seq_sv = hv_fetch(hash, "_seq", 4, 0);
131            
132 1 50         if (!fp_sv || !seq_sv)
    50          
133 0           return;
134            
135             // Check if pointers are valid before cleanup
136 1 50         if (SvOK(*fp_sv) && SvIV(*fp_sv) != 0) {
    50          
137 1           fp = INT2PTR(gzFile, SvIV(*fp_sv));
138 1           gzclose(fp);
139             // Mark as cleaned up
140 1           sv_setiv(*fp_sv, 0);
141             }
142            
143 1 50         if (SvOK(*seq_sv) && SvIV(*seq_sv) != 0) {
    50          
144 1           seq = INT2PTR(kseq_t*, SvIV(*seq_sv));
145 1           kseq_destroy(seq);
146             // Mark as cleaned up
147 1           sv_setiv(*seq_sv, 0);
148             }