1 /*===========================================================================
2 *
3 *                            PUBLIC DOMAIN NOTICE
4 *               National Center for Biotechnology Information
5 *
6 *  This software/database is a "United States Government Work" under the
7 *  terms of the United States Copyright Act.  It was written as part of
8 *  the author's official duties as a United States Government employee and
9 *  thus cannot be copyrighted.  This software/database is freely available
10 *  to the public for use. The National Library of Medicine and the U.S.
11 *  Government have not placed any restriction on its use or reproduction.
12 *
13 *  Although all reasonable efforts have been taken to ensure the accuracy
14 *  and reliability of the software and data, the NLM and the U.S.
15 *  Government do not and cannot warrant the performance or results that
16 *  may be obtained by using this software or data. The NLM and the U.S.
17 *  Government disclaim all warranties, express or implied, including
18 *  warranties of performance, merchantability or fitness for any particular
19 *  purpose.
20 *
21 *  Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26 
27 #include "CSRA1_Alignment.h"
28 
29 typedef struct BAM_Alignment BAM_Alignment;
30 #define NGS_ALIGNMENT void
31 
32 #include "NGS_Alignment.h"
33 
34 #include "NGS_ReadCollection.h"
35 
36 #include <sysalloc.h>
37 
38 #include <vdb/cursor.h>
39 #include <vdb/vdb-priv.h>
40 
41 #include <klib/printf.h>
42 #include <klib/rc.h>
43 
44 #include <kfc/ctx.h>
45 #include <kfc/rsrc.h>
46 #include <kfc/except.h>
47 #include <kfc/xc.h>
48 
49 #include "NGS_Refcount.h"
50 #include "NGS_String.h"
51 
52 #include <string.h>
53 #include <limits.h>
54 
55 #include "BAM_Record.h"
56 
57 struct BAM_Alignment {
58     NGS_Alignment super;
59     struct BAM_Record *(*provider_f)(struct NGS_ReadCollection *, ctx_t);
60     struct NGS_ReadCollection *provider;
61     BAM_Record *cur;
62     bool primary;
63     bool secondary;
64 };
65 
BAM_AlignmentWhack(void * const vp,ctx_t ctx)66 static void BAM_AlignmentWhack(void * const vp, ctx_t ctx)
67 {
68     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
69     BAM_Alignment *const self = (BAM_Alignment *)vp;
70 
71     free(self->cur);
72     NGS_RefcountRelease(&self->provider->dad, ctx);
73 }
74 
BAM_AlignmentAlignmentId(void * const vp,ctx_t ctx)75 static NGS_String *BAM_AlignmentAlignmentId(void *const vp, ctx_t ctx)
76 {
77     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
78     BAM_Alignment *const self = (BAM_Alignment *)vp;
79 
80     (void)self;
81     UNIMPLEMENTED();
82     return NULL;
83 }
84 
BAM_AlignmentReferenceSpec(void * const vp,ctx_t ctx)85 static NGS_String * BAM_AlignmentReferenceSpec(void *const vp, ctx_t ctx)
86 {
87     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
88     BAM_Alignment *const self = (BAM_Alignment *)vp;
89 
90     if (self->cur)
91         return NGS_StringMake(ctx, self->cur->RNAME, strlen(self->cur->RNAME));
92 
93     USER_ERROR(xcRowNotFound, "no current row");
94     return NULL;
95 }
96 
97 
BAM_AlignmentMappingQuality(void * const vp,ctx_t ctx)98 static int BAM_AlignmentMappingQuality(void *const vp, ctx_t ctx)
99 {
100     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
101     BAM_Alignment *const self = (BAM_Alignment *)vp;
102 
103     if (self->cur)
104         return self->cur->MAPQ;
105 
106     USER_ERROR(xcRowNotFound, "no current row");
107     return 0;
108 }
109 
110 
BAM_AlignmentReferenceBases(void * const vp,ctx_t ctx)111 static NGS_String * BAM_AlignmentReferenceBases(void *const vp, ctx_t ctx)
112 {
113     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
114     BAM_Alignment *const self = (BAM_Alignment *)vp;
115 
116     (void)self;
117     UNIMPLEMENTED();
118     return NULL;
119 }
120 
121 
FindRG(void * const vp,ctx_t ctx,unsigned const ord,BAM_Record_Extra_Field const * const fld)122 static bool FindRG(void *const vp, ctx_t ctx, unsigned const ord, BAM_Record_Extra_Field const *const fld)
123 {
124     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
125 
126     if (fld->tag[0] == 'R' && fld->tag[1] == 'G' && fld->val_type == 'Z') {
127         NGS_String **const prslt = vp;
128 
129         *prslt = NGS_StringMakeCopy(ctx, fld->value->string, fld->elemcount);
130         return false; /* done */
131     }
132     return true; /* keep going */
133 }
134 
BAM_AlignmentReadGroup(void * const vp,ctx_t ctx)135 static NGS_String * BAM_AlignmentReadGroup(void *const vp, ctx_t ctx)
136 {
137     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
138     BAM_Alignment *const self = (BAM_Alignment *)vp;
139 
140     if (self->cur) {
141         NGS_String *rslt = NULL;
142 
143         BAM_Record_ForEachExtra(self->cur, ctx, FindRG, &rslt);
144         return rslt;
145     }
146     USER_ERROR(xcRowNotFound, "no current row");
147     return NULL;
148 }
149 
150 
BAM_AlignmentReadId(void * const vp,ctx_t ctx)151 static NGS_String * BAM_AlignmentReadId(void *const vp, ctx_t ctx)
152 {
153     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
154     BAM_Alignment *const self = (BAM_Alignment *)vp;
155 
156     if (self->cur)
157         return self->cur->QNAME ? NGS_StringMake(ctx, self->cur->QNAME, strlen(self->cur->QNAME)) : NULL;
158 
159     USER_ERROR(xcRowNotFound, "no current row");
160     return NULL;
161 }
162 
163 
164 typedef struct {
165     unsigned start;
166     unsigned length;
167 } clipped_t;
168 
get_clipping(BAM_Record const * rec)169 static clipped_t const get_clipping(BAM_Record const *rec)
170 {
171     clipped_t rslt = { 0, rec->seqlen };
172 
173     if (rec->ncigar > 0 && (rec->cigar[0] & 0x0F) == 4) {
174         unsigned const length = rec->cigar[0] >> 4;
175 
176         rslt.start += length;
177         rslt.length -= length;
178     }
179     if (rec->ncigar > 1 && (rec->cigar[rec->ncigar - 1] & 0x0F) == 4) {
180         unsigned const length = rec->cigar[rec->ncigar - 1] >> 4;
181 
182         rslt.length -= length;
183     }
184     return rslt;
185 }
186 
BAM_AlignmentClippedFragmentBases(void * const vp,ctx_t ctx)187 static NGS_String * BAM_AlignmentClippedFragmentBases(void *const vp, ctx_t ctx)
188 {
189     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
190     BAM_Alignment *const self = (BAM_Alignment *)vp;
191 
192     if (self->cur) {
193         if (self->cur->seqlen) {
194             clipped_t const clipping = get_clipping(self->cur);
195             return NGS_StringMake(ctx, self->cur->SEQ + clipping.start, clipping.length);
196         }
197         return NULL;
198     }
199     USER_ERROR(xcRowNotFound, "no current row");
200     return NULL;
201 }
202 
203 
BAM_AlignmentClippedFragmentQualities(void * const vp,ctx_t ctx)204 static NGS_String * BAM_AlignmentClippedFragmentQualities(void *const vp, ctx_t ctx)
205 {
206     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
207     BAM_Alignment *const self = (BAM_Alignment *)vp;
208 
209     if (self->cur) {
210         if (self->cur->seqlen && self->cur->QUAL[0] != -1) {
211             clipped_t const clipping = get_clipping(self->cur);
212             return NGS_StringMake(ctx, self->cur->QUAL + clipping.start, clipping.length);
213         }
214         return NULL;
215     }
216     USER_ERROR(xcRowNotFound, "no current row");
217     return NULL;
218 }
219 
220 
BAM_AlignmentIsPrimary(void * const vp,ctx_t ctx)221 static bool BAM_AlignmentIsPrimary(void *const vp, ctx_t ctx)
222 {
223     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
224     BAM_Alignment *const self = (BAM_Alignment *)vp;
225 
226     if (self->cur)
227         return (self->cur->FLAG & 0x0900) == 0 ? true : false;
228 
229     USER_ERROR(xcRowNotFound, "no current row");
230     return false;
231 }
232 
233 
BAM_AlignmentAlignmentPosition(void * const vp,ctx_t ctx)234 static int64_t BAM_AlignmentAlignmentPosition(void *const vp, ctx_t ctx)
235 {
236     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
237     BAM_Alignment *const self = (BAM_Alignment *)vp;
238 
239     if (self->cur)
240         return self->cur->POS - 1;
241 
242     USER_ERROR(xcRowNotFound, "no current row");
243     return -1;
244 }
245 
246 
ComputeRefLen(size_t const count,uint32_t const cigar[])247 static unsigned ComputeRefLen(size_t const count, uint32_t const cigar[])
248 {
249     unsigned rslt = 0;
250     unsigned i;
251 
252     for (i = 0; i < count; ++i) {
253         uint32_t const op = cigar[i];
254         unsigned const len = op >> 4;
255         int const code = op & 0x0F;
256 
257         switch (code) {
258         case 0: /* M */
259         case 2: /* D */
260         case 3: /* N */
261         case 7: /* = */
262         case 8: /* X */
263             rslt += len;
264             break;
265         }
266     }
267     return rslt;
268 }
269 
BAM_AlignmentAlignmentLength(void * const vp,ctx_t ctx)270 static uint64_t BAM_AlignmentAlignmentLength(void *const vp, ctx_t ctx)
271 {
272     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
273     BAM_Alignment *const self = (BAM_Alignment *)vp;
274 
275     if (self->cur)
276         return ComputeRefLen(self->cur->ncigar, self->cur->cigar);
277 
278     USER_ERROR(xcRowNotFound, "no current row");
279     return 0;
280 }
281 
282 
BAM_AlignmentIsReversedOrientation(void * const vp,ctx_t ctx)283 static bool BAM_AlignmentIsReversedOrientation(void *const vp, ctx_t ctx)
284 {
285     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
286     BAM_Alignment *const self = (BAM_Alignment *)vp;
287 
288     if (self->cur)
289         return (self->cur->FLAG & 0x0010) == 0 ? false : true;
290 
291     USER_ERROR(xcRowNotFound, "no current row");
292     return false;
293 }
294 
295 
BAM_AlignmentSoftClip(void * const vp,ctx_t ctx,bool left)296 static int BAM_AlignmentSoftClip(void *const vp, ctx_t ctx, bool left)
297 {
298     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
299     BAM_Alignment *const self = (BAM_Alignment *)vp;
300 
301     if (self->cur) {
302         unsigned const end = left ? 0 : (self->cur->ncigar - 1);
303         uint32_t const op = self->cur->cigar[end];
304         int const code = op & 0x0F;
305         int const len = op >> 4;
306 
307         return code == 4 ? len : 0;
308     }
309     USER_ERROR(xcRowNotFound, "no current row");
310     return false;
311 }
312 
313 
BAM_AlignmentTemplateLength(void * const vp,ctx_t ctx)314 static uint64_t BAM_AlignmentTemplateLength(void *const vp, ctx_t ctx)
315 {
316     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
317     BAM_Alignment *const self = (BAM_Alignment *)vp;
318 
319     if (self->cur)
320         return self->cur->TLEN;
321 
322     USER_ERROR(xcRowNotFound, "no current row");
323     return 0;
324 }
325 
326 
FormatCIGAR(char * dst,char const OPCODE[],size_t const count,uint32_t const cigar[])327 static char const *FormatCIGAR(char *dst, char const OPCODE[], size_t const count, uint32_t const cigar[])
328 {
329     uint32_t const *src = cigar + count;
330     unsigned i;
331     char *last_out;
332     char last_code = 0;
333     uint32_t last_len = 0;
334 
335     last_out = dst;
336     for (i = 0; i < count; ++i) {
337         uint32_t const op = *--src;
338         char const code = OPCODE[op & 0x0F];
339         uint32_t const len1 = op >> 4;
340         uint32_t len = code == last_code ? ((dst = last_out), last_len + len1) : len1;
341 
342         last_len = len;
343         last_code = code;
344         last_out = dst;
345         *--dst = code;
346         for ( ; ; ) {
347             *--dst = len % 10 + '0';
348             if ((len /= 10) == 0)
349                 break;
350         }
351     }
352     return dst;
353 }
354 
CIGAR(ctx_t ctx,char const OPCODE[],size_t const count,uint32_t const cigar[])355 static NGS_String *CIGAR(ctx_t ctx, char const OPCODE[], size_t const count, uint32_t const cigar[])
356 {
357     size_t const max = 10 * count;
358 #if DEBUG
359     char buffer[max + 1];
360     buffer[max] = '\0';
361 #else
362     char buffer[max];
363 #endif
364     char *const endp = buffer + max;
365     char const *const rslt = FormatCIGAR(endp, OPCODE, count, cigar);
366     size_t const len = endp - rslt;
367 
368     return NGS_StringMakeCopy(ctx, rslt, len);
369 }
370 
CIGAR_clipped(ctx_t ctx,char const OPCODE[],bool const clipped,size_t const count,uint32_t const cigar[])371 static NGS_String *CIGAR_clipped(ctx_t ctx, char const OPCODE[], bool const clipped, size_t const count, uint32_t const cigar[])
372 {
373     if (!clipped)
374         return CIGAR(ctx, OPCODE, count, cigar);
375     else {
376         char const first = cigar[0] & 0x0F;
377         char const last  = cigar[count - 1] & 0x0F;
378         unsigned const cfirst = (first == 4 || first == 5) ? 1 : 0;
379         unsigned const clast  = (last  == 4 || last  == 5) ? 1 : 0;
380 
381         return CIGAR(ctx, OPCODE, count - cfirst - clast, &cigar[cfirst]);
382     }
383 }
384 
BAM_AlignmentShortCigar(void * const vp,ctx_t ctx,bool clipped)385 static NGS_String * BAM_AlignmentShortCigar(void *const vp, ctx_t ctx, bool clipped)
386 {
387     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
388     BAM_Alignment *const self = (BAM_Alignment *)vp;
389 
390     if (self->cur)
391         return CIGAR_clipped(ctx, "MIDNSHPMM???????", clipped, self->cur->ncigar, self->cur->cigar);
392 
393     USER_ERROR(xcRowNotFound, "no current row");
394     return NULL;
395 }
396 
397 
BAM_AlignmentLongCigar(void * const vp,ctx_t ctx,bool clipped)398 static NGS_String * BAM_AlignmentLongCigar(void *const vp, ctx_t ctx, bool clipped)
399 {
400     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
401     BAM_Alignment *const self = (BAM_Alignment *)vp;
402 
403     if (self->cur)
404         return CIGAR_clipped(ctx, "MIDNSHP=X???????", clipped, self->cur->ncigar, self->cur->cigar);
405 
406     USER_ERROR(xcRowNotFound, "no current row");
407     return NULL;
408 }
409 
410 
BAM_AlignmentHasMate(void * const vp,ctx_t ctx)411 static bool BAM_AlignmentHasMate(void *const vp, ctx_t ctx)
412 {
413     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
414     BAM_Alignment *const self = (BAM_Alignment *)vp;
415 
416     if (self->cur)
417         return (self->cur->FLAG & 0x0001) == 0 ? false : true;
418 
419     USER_ERROR(xcRowNotFound, "no current row");
420     return false;
421 }
422 
423 
BAM_AlignmentMateAlignmentId(void * const vp,ctx_t ctx)424 static NGS_String * BAM_AlignmentMateAlignmentId(void *const vp, ctx_t ctx)
425 {
426     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
427     BAM_Alignment *const self = (BAM_Alignment *)vp;
428 
429     (void)self;
430     UNIMPLEMENTED();
431     return 0;
432 }
433 
434 
BAM_AlignmentMateAlignment(void * const vp,ctx_t ctx)435 static void * BAM_AlignmentMateAlignment(void *const vp, ctx_t ctx)
436 {
437     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
438     BAM_Alignment *const self = (BAM_Alignment *)vp;
439 
440     (void)self;
441     UNIMPLEMENTED();
442     return NULL;
443 }
444 
445 
BAM_AlignmentMateReferenceSpec(void * const vp,ctx_t ctx)446 static NGS_String * BAM_AlignmentMateReferenceSpec(void *const vp, ctx_t ctx)
447 {
448     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
449     BAM_Alignment *const self = (BAM_Alignment *)vp;
450 
451     if (self->cur)
452         return self->cur->RNEXT ? NGS_StringMake(ctx, self->cur->RNEXT, strlen(self->cur->RNEXT)) : NULL;
453 
454     USER_ERROR(xcRowNotFound, "no current row");
455     return NULL;
456 }
457 
458 
BAM_AlignmentMateIsReversedOrientation(void * const vp,ctx_t ctx)459 static bool BAM_AlignmentMateIsReversedOrientation(void *const vp, ctx_t ctx)
460 {
461     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
462     BAM_Alignment *const self = (BAM_Alignment *)vp;
463 
464     if (self->cur)
465         return (self->cur->FLAG & 0x0020) == 0 ? false : true;
466 
467     USER_ERROR(xcRowNotFound, "no current row");
468     return false;
469 }
470 
BAM_AlignmentIsFirst(void * const vp,ctx_t ctx)471 static bool BAM_AlignmentIsFirst(void *const vp, ctx_t ctx)
472 {
473     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
474     BAM_Alignment *const self = (BAM_Alignment *)vp;
475 
476     if (self->cur) {
477         bool const isMated = (self->cur->FLAG & 0x001) == 0 ? false : true;
478         bool const isFirst = (self->cur->FLAG & 0x040) == 0 ? false : true;
479         bool const isLast  = (self->cur->FLAG & 0x080) == 0 ? false : true;
480         return (isMated && isFirst && !isLast);
481     }
482     USER_ERROR(xcRowNotFound, "no current row");
483     return false;
484 }
485 
486 
487 /*--------------------------------------------------------------------------
488  * NGS_AlignmentIterator
489  */
490 
ShouldSkip(BAM_Alignment const * const self)491 static bool ShouldSkip(BAM_Alignment const *const self)
492 {
493     if (!self->cur->RNAME) /* not aligned */
494         return true;
495 
496     if ((self->cur->FLAG & 0x0900) == 0 && !self->primary) /* is primary and don't want primary */
497         return true;
498 
499     if ((self->cur->FLAG & 0x0900) != 0 && !self->secondary) /* is secondary and don't want secondary */
500         return true;
501 
502     return false;
503 }
504 
BAM_AlignmentIteratorNext(void * const vp,ctx_t ctx)505 static bool BAM_AlignmentIteratorNext(void *const vp, ctx_t ctx)
506 {
507     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
508     BAM_Alignment *const self = (BAM_Alignment *)vp;
509 
510     do {
511         if (self->cur)
512             free(self->cur);
513         self->cur = self->provider_f(self->provider, ctx);
514         if (FAILED() || !self->cur)
515             break;
516     } while (ShouldSkip(self));
517 
518     return self->cur != NULL;
519 }
520 
521 
BAM_AlignmentFragmentGetId(void * const vp,ctx_t ctx)522 static NGS_String * BAM_AlignmentFragmentGetId(void *const vp, ctx_t ctx)
523 {
524     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
525     BAM_Alignment *const self = (BAM_Alignment *)vp;
526 
527     if (self->cur) {
528         return self->cur->QNAME ? NGS_StringMake(ctx, self->cur->QNAME, strlen(self->cur->QNAME)) : NGS_StringMake(ctx, "", 0);
529     }
530     USER_ERROR(xcRowNotFound, "no current row");
531     return NULL;
532 }
533 
534 
BAM_AlignmentFragmentGetBases(void * const vp,ctx_t ctx,uint64_t offset,uint64_t length)535 static NGS_String * BAM_AlignmentFragmentGetBases(void *const vp, ctx_t ctx,
536                                                   uint64_t offset, uint64_t length)
537 {
538     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
539     BAM_Alignment *const self = (BAM_Alignment *)vp;
540 
541     if (self->cur) {
542         if (offset + length < self->cur->seqlen) {
543             return NGS_StringMake(ctx, self->cur->SEQ + offset, length);
544         }
545         USER_ERROR(xcRowNotFound, "invalid offset or length");
546         return NULL;
547     }
548     USER_ERROR(xcRowNotFound, "no current row");
549     return NULL;
550 }
551 
552 
BAM_AlignmentFragmentGetQualities(void * const vp,ctx_t ctx,uint64_t offset,uint64_t length)553 static NGS_String * BAM_AlignmentFragmentGetQualities(void *const vp, ctx_t ctx,
554                                                       uint64_t offset, uint64_t length)
555 {
556     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
557     BAM_Alignment *const self = (BAM_Alignment *)vp;
558 
559     if (self->cur) {
560         if (offset + length < self->cur->seqlen) {
561             return NGS_StringMake(ctx, self->cur->QUAL + offset, length);
562         }
563         USER_ERROR(xcRowNotFound, "invalid offset or length");
564         return NULL;
565     }
566     USER_ERROR(xcRowNotFound, "no current row");
567     return NULL;
568 }
569 
570 
BAM_AlignmentFragmentNext(void * const vp,ctx_t ctx)571 static bool BAM_AlignmentFragmentNext(void *const vp, ctx_t ctx)
572 {
573     FUNC_ENTRY(ctx, rcSRA, rcFile, rcAccessing);
574     BAM_Alignment *const self = (BAM_Alignment *)vp;
575 
576     (void)self;
577     UNIMPLEMENTED();
578     return NULL;
579 }
580 
581 
582 
583 static NGS_Alignment_vt const vt =
584 {
585     {
586         {
587             /* NGS_Refcount */
588             BAM_AlignmentWhack
589         },
590 
591         /* NGS_Fragment */
592         BAM_AlignmentFragmentGetId,
593         BAM_AlignmentFragmentGetBases,
594         BAM_AlignmentFragmentGetQualities,
595         BAM_AlignmentFragmentNext
596     },
597 
598     BAM_AlignmentAlignmentId,
599     BAM_AlignmentReferenceSpec,
600     BAM_AlignmentMappingQuality,
601     BAM_AlignmentReferenceBases,
602     BAM_AlignmentReadGroup,
603     BAM_AlignmentReadId,
604     BAM_AlignmentClippedFragmentBases,
605     BAM_AlignmentClippedFragmentQualities,
606     NULL,
607     BAM_AlignmentIsPrimary,
608     BAM_AlignmentAlignmentPosition,
609     BAM_AlignmentAlignmentLength,
610     BAM_AlignmentIsReversedOrientation,
611     BAM_AlignmentSoftClip,
612     BAM_AlignmentTemplateLength,
613     BAM_AlignmentShortCigar,
614     BAM_AlignmentLongCigar,
615     BAM_AlignmentHasMate,
616     BAM_AlignmentMateAlignmentId,
617     BAM_AlignmentMateAlignment,
618     BAM_AlignmentMateReferenceSpec,
619     BAM_AlignmentMateIsReversedOrientation,
620     BAM_AlignmentIsFirst,
621 
622     /* Iterator */
623     BAM_AlignmentIteratorNext
624 };
625 
BAM_AlignmentInit(BAM_Alignment * const self,ctx_t ctx,bool const primary,bool const secondary,struct BAM_Record * (* const provider_f)(struct NGS_ReadCollection *,ctx_t),struct NGS_ReadCollection * const provider)626 static void BAM_AlignmentInit(BAM_Alignment *const self, ctx_t ctx, bool const primary, bool const secondary,
627                               struct BAM_Record *(*const provider_f)(struct NGS_ReadCollection *, ctx_t),
628                               struct NGS_ReadCollection *const provider)
629 {
630     self->provider = provider;
631     self->provider_f = provider_f;
632     self->primary = primary;
633     self->secondary = secondary;
634 }
635 
BAM_AlignmentMake(ctx_t ctx,bool const primary,bool const secondary,struct BAM_Record * (* const provider_f)(struct NGS_ReadCollection *,ctx_t),struct NGS_ReadCollection * const provider,char const name[])636 struct NGS_Alignment *BAM_AlignmentMake(ctx_t ctx, bool const primary, bool const secondary,
637                                         struct BAM_Record *(*const provider_f)(struct NGS_ReadCollection *, ctx_t),
638                                         struct NGS_ReadCollection *const provider,
639                                         char const name[])
640 {
641     FUNC_ENTRY(ctx, rcSRA, rcFile, rcReading);
642     void *self = calloc(1, sizeof(BAM_Alignment));
643     if (self) {
644         NGS_Alignment *const super = &((BAM_Alignment *)self)->super;
645 
646         TRY(NGS_AlignmentInit(ctx, super, &vt, "BAM_Alignment", name)) {
647             TRY(BAM_AlignmentInit(self, ctx, primary, secondary, provider_f, provider)) {
648                 return self;
649             }
650         }
651         free(self);
652     }
653     else {
654         SYSTEM_ABORT(xcNoMemory, "allocating BAM_Alignment ( '%s' )", name);
655     }
656     return NULL;
657 }
658