Patched the example makefile to not use samtools pileup, deprecated.
[samtools.git] / bam.c
diff --git a/bam.c b/bam.c
index 94b0aa8bb85bef4ae4a787af3337f1765ed8899e..5fac17df6ec27d7cbb04b5600c3ce54d5c06b354 100644 (file)
--- a/bam.c
+++ b/bam.c
@@ -7,7 +7,7 @@
 #include "kstring.h"
 #include "sam_header.h"
 
-int bam_is_be = 0;
+int bam_is_be = 0, bam_verbose = 2;
 char *bam_flag2char_table = "pPuUrR12sfd\0\0\0\0\0";
 
 /**************************
@@ -79,7 +79,7 @@ bam_header_t *bam_header_read(bamFile fp)
                // with ESPIPE.  Suppress the error message in this case.
                if (errno != ESPIPE) perror("[bam_header_read] bgzf_check_EOF");
        }
-       else if (i == 0) fprintf(stderr, "[bam_header_read] EOF marker is absent.\n");
+       else if (i == 0) fprintf(stderr, "[bam_header_read] EOF marker is absent. The input is probably truncated.\n");
        // read "BAM1"
        magic_len = bam_read(fp, buf, 4);
        if (magic_len != 4 || strncmp(buf, "BAM\001", 4) != 0) {
@@ -160,6 +160,19 @@ static void swap_endian_data(const bam1_core_t *c, int data_len, uint8_t *data)
                else if (type == 'I' || type == 'F') { bam_swap_endian_4p(s); s += 4; }
                else if (type == 'D') { bam_swap_endian_8p(s); s += 8; }
                else if (type == 'Z' || type == 'H') { while (*s) ++s; ++s; }
+               else if (type == 'B') {
+                       int32_t n, Bsize = bam_aux_type2size(*s);
+                       memcpy(&n, s + 1, 4);
+                       if (1 == Bsize) {
+                       } else if (2 == Bsize) {
+                               for (i = 0; i < n; i += 2)
+                                       bam_swap_endian_2p(s + 5 + i);
+                       } else if (4 == Bsize) {
+                               for (i = 0; i < n; i += 4)
+                                       bam_swap_endian_4p(s + 5 + i);
+                       }
+                       bam_swap_endian_4p(s+1); 
+               }
        }
 }
 
@@ -245,7 +258,11 @@ char *bam_format1_core(const bam_header_t *header, const bam1_t *b, int of)
                kputc('\t', &str);
        }
        if (c->tid < 0) kputsn("*\t", 2, &str);
-       else { kputs(header->target_name[c->tid], &str); kputc('\t', &str); }
+       else {
+               if (header) kputs(header->target_name[c->tid] , &str);
+               else kputw(c->tid, &str);
+               kputc('\t', &str);
+       }
        kputw(c->pos + 1, &str); kputc('\t', &str); kputw(c->qual, &str); kputc('\t', &str);
        if (c->n_cigar == 0) kputc('*', &str);
        else {
@@ -257,7 +274,11 @@ char *bam_format1_core(const bam_header_t *header, const bam1_t *b, int of)
        kputc('\t', &str);
        if (c->mtid < 0) kputsn("*\t", 2, &str);
        else if (c->mtid == c->tid) kputsn("=\t", 2, &str);
-       else { kputs(header->target_name[c->mtid], &str); kputc('\t', &str); }
+       else {
+               if (header) kputs(header->target_name[c->mtid], &str);
+               else kputw(c->mtid, &str);
+               kputc('\t', &str);
+       }
        kputw(c->mpos + 1, &str); kputc('\t', &str); kputw(c->isize, &str); kputc('\t', &str);
        if (c->l_qseq) {
                for (i = 0; i < c->l_qseq; ++i) kputc(bam_nt16_rev_table[bam1_seqi(s, i)], &str);
@@ -281,6 +302,23 @@ char *bam_format1_core(const bam_header_t *header, const bam1_t *b, int of)
                else if (type == 'f') { ksprintf(&str, "f:%g", *(float*)s); s += 4; }
                else if (type == 'd') { ksprintf(&str, "d:%lg", *(double*)s); s += 8; }
                else if (type == 'Z' || type == 'H') { kputc(type, &str); kputc(':', &str); while (*s) kputc(*s++, &str); ++s; }
+               else if (type == 'B') {
+                       uint8_t sub_type = *(s++);
+                       int32_t n;
+                       memcpy(&n, s, 4);
+                       s += 4; // no point to the start of the array
+                       kputc(type, &str); kputc(':', &str); kputc(sub_type, &str); // write the typing
+                       for (i = 0; i < n; ++i) {
+                               kputc(',', &str);
+                               if ('c' == sub_type || 'c' == sub_type) { kputw(*(int8_t*)s, &str); ++s; }
+                               else if ('C' == sub_type) { kputw(*(uint8_t*)s, &str); ++s; }
+                               else if ('s' == sub_type) { kputw(*(int16_t*)s, &str); s += 2; }
+                               else if ('S' == sub_type) { kputw(*(uint16_t*)s, &str); s += 2; }
+                               else if ('i' == sub_type) { kputw(*(int32_t*)s, &str); s += 4; }
+                               else if ('I' == sub_type) { kputuw(*(uint32_t*)s, &str); s += 4; }
+                               else if ('f' == sub_type) { ksprintf(&str, "%g", *(float*)s); s += 4; }
+                       }
+               }
        }
        return str.s;
 }
@@ -297,6 +335,22 @@ void bam_view1(const bam_header_t *header, const bam1_t *b)
        free(s);
 }
 
+int bam_validate1(const bam_header_t *header, const bam1_t *b)
+{
+       char *s;
+
+       if (b->core.tid < -1 || b->core.mtid < -1) return 0;
+       if (header && (b->core.tid >= header->n_targets || b->core.mtid >= header->n_targets)) return 0;
+
+       if (b->data_len < b->core.l_qname) return 0;
+       s = memchr(bam1_qname(b), '\0', b->core.l_qname);
+       if (s != &bam1_qname(b)[b->core.l_qname-1]) return 0;
+
+       // FIXME: Other fields could also be checked, especially the auxiliary data
+
+       return 1;
+}
+
 // FIXME: we should also check the LB tag associated with each alignment
 const char *bam_get_library(bam_header_t *h, const bam1_t *b)
 {