]> git.donarmstrong.com Git - samtools.git/commitdiff
* fixed a bug in kstrtok@kstring.c
authorHeng Li <lh3@live.co.uk>
Mon, 9 Aug 2010 16:49:23 +0000 (16:49 +0000)
committerHeng Li <lh3@live.co.uk>
Mon, 9 Aug 2010 16:49:23 +0000 (16:49 +0000)
 * preliminary VCF parser (not parse everything for now)
 * improved view interface

bcftools/bcf.c
bcftools/bcf.h
bcftools/bcfutils.c
bcftools/main.c
bcftools/vcf.c
bcftools/vcfout.c
bgzf.c
kstring.c

index f6c26f2db2e248c05ffefe34642a5a68b33ae95b..fdc13b83f4ea7f714e159afbf6ba1e761fe42d60 100644 (file)
@@ -204,41 +204,52 @@ static inline void fmt_str(const char *p, kstring_t *s)
        else kputs(p, s);
 }
 
-char *bcf_fmt(const bcf_hdr_t *h, bcf1_t *b)
+void bcf_fmt_core(const bcf_hdr_t *h, bcf1_t *b, kstring_t *s)
 {
-       kstring_t s;
        int i, j, x;
-       memset(&s, 0, sizeof(kstring_t));
-       kputs(h->ns[b->tid], &s); kputc('\t', &s);
-       kputw(b->pos + 1, &s); kputc('\t', &s);
-       fmt_str(b->str, &s); kputc('\t', &s);
-       fmt_str(b->ref, &s); kputc('\t', &s);
-       fmt_str(b->alt, &s); kputc('\t', &s);
-       kputw(b->qual, &s); kputc('\t', &s);
-       fmt_str(b->flt, &s); kputc('\t', &s);
-       fmt_str(b->info, &s);
+       s->l = 0;
+       kputs(h->ns[b->tid], s); kputc('\t', s);
+       kputw(b->pos + 1, s); kputc('\t', s);
+       fmt_str(b->str, s); kputc('\t', s);
+       fmt_str(b->ref, s); kputc('\t', s);
+       fmt_str(b->alt, s); kputc('\t', s);
+       kputw(b->qual, s); kputc('\t', s);
+       fmt_str(b->flt, s); kputc('\t', s);
+       fmt_str(b->info, s);
        if (b->fmt[0]) {
-               kputc('\t', &s);
-               fmt_str(b->fmt, &s);
+               kputc('\t', s);
+               fmt_str(b->fmt, s);
        }
        x = b->n_alleles * (b->n_alleles + 1) / 2;
        for (j = 0; j < h->n_smpl; ++j) {
-               kputc('\t', &s);
+               kputc('\t', s);
                for (i = 0; i < b->n_gi; ++i) {
-                       if (i) kputc(':', &s);
+                       if (i) kputc(':', s);
                        if (b->gi[i].fmt == bcf_str2int("PL", 2)) {
                                uint8_t *d = (uint8_t*)b->gi[i].data + j * x;
                                int k;
                                for (k = 0; k < x; ++k) {
-                                       if (k > 0) kputc(',', &s);
-                                       kputw(d[k], &s);
+                                       if (k > 0) kputc(',', s);
+                                       kputw(d[k], s);
                                }
                        } else if (b->gi[i].fmt == bcf_str2int("DP", 2)) {
-                               kputw(((uint16_t*)b->gi[i].data)[j], &s);
+                               kputw(((uint16_t*)b->gi[i].data)[j], s);
                        } else if (b->gi[i].fmt == bcf_str2int("GQ", 2)) {
-                               kputw(((uint8_t*)b->gi[i].data)[j], &s);
+                               kputw(((uint8_t*)b->gi[i].data)[j], s);
+                       } else if (b->gi[i].fmt == bcf_str2int("GT", 2)) {
+                               int y = ((uint8_t*)b->gi[i].data)[j];
+                               kputc('0' + (y>>3&7), s);
+                               kputc("/|"[y>>6&1], s);
+                               kputc('0' + (y&7), s);
                        }
                }
        }
+}
+
+char *bcf_fmt(const bcf_hdr_t *h, bcf1_t *b)
+{
+       kstring_t s;
+       s.l = s.m = 0; s.s = 0;
+       bcf_fmt_core(h, b, &s);
        return s.s;
 }
index 3c0ab2cf8a71853a51361eca248bd0df342b423e..c317440a21fafbe2334a77efd48f8b05d9d8681e 100644 (file)
@@ -58,11 +58,18 @@ extern "C" {
        int bcf_destroy(bcf1_t *b);
        char *bcf_fmt(const bcf_hdr_t *h, bcf1_t *b);
 
+       bcf_t *vcf_open(const char *fn, const char *mode);
        int vcf_close(bcf_t *bp);
+       bcf_hdr_t *vcf_hdr_read(bcf_t *bp);
+       int vcf_hdr_write(bcf_t *bp, const bcf_hdr_t *h);
+       int vcf_write(bcf_t *bp, bcf_hdr_t *h, bcf1_t *b);
+       int vcf_read(bcf_t *bp, bcf_hdr_t *h, bcf1_t *b);
 
        void *bcf_build_refhash(bcf_hdr_t *h);
        void bcf_str2id_destroy(void *_hash);
+       int bcf_str2id_add(void *_hash, const char *str);
        int bcf_str2id(void *_hash, const char *str);
+       void *bcf_str2id_init();
 
        int bcf_idx_build(const char *fn);
        uint64_t bcf_idx_query(const bcf_idx_t *idx, int tid, int beg, int end);
index 861e33fa6bf1a9e24955b9c3f459d6d248a83b5a..3010ef3435bb240fff5ee2a2fb1485701b1628a3 100644 (file)
@@ -20,11 +20,6 @@ void *bcf_str2id_init()
        return kh_init(str2id);
 }
 
-int bcf_str2id_put(void *_hash, const char *str, int id)
-{
-       return 0;
-}
-
 void bcf_str2id_destroy(void *_hash)
 {
        khash_t(str2id) *hash = (khash_t(str2id)*)_hash;
@@ -40,3 +35,14 @@ int bcf_str2id(void *_hash, const char *str)
        return k == kh_end(hash)? -1 : kh_val(hash, k);
 }
 
+int bcf_str2id_add(void *_hash, const char *str)
+{
+       khint_t k;
+       int ret;
+       khash_t(str2id) *hash = (khash_t(str2id)*)_hash;
+       if (!hash) return -1;
+       k = kh_put(str2id, hash, str, &ret);
+       if (ret == 0) return kh_val(hash, k);
+       kh_val(hash, k) = kh_size(hash) - 1;
+       return kh_val(hash, k);
+}
index 21d9eec29f58f4561967c85af0ee7a39edc4f374..e271efd6b3afb6b7f63b9d317da4a849959e4072 100644 (file)
@@ -4,7 +4,6 @@
 
 int bcfview(int argc, char *argv[]);
 int bcf_main_index(int argc, char *argv[]);
-int vcf_test(int argc, char *argv[]);
 
 int main(int argc, char *argv[])
 {
@@ -18,7 +17,6 @@ int main(int argc, char *argv[])
        }
        if (strcmp(argv[1], "view") == 0) return bcfview(argc-1, argv+1);
        if (strcmp(argv[1], "index") == 0) return bcf_main_index(argc-1, argv+1);
-       if (strcmp(argv[1], "test") == 0) return vcf_test(argc-1, argv+1);
        else {
                fprintf(stderr, "[main] Unrecognized command.\n");
                return 1;
index 81a5777af035aabe045ff74de751b9e13dfb576a..50a73566a6d6e45dca212e909ca36d10580dcd0e 100644 (file)
@@ -22,7 +22,7 @@ bcf_hdr_t *vcf_hdr_read(bcf_t *bp)
        int dret;
        vcf_t *v;
        bcf_hdr_t *h;
-       if (!bp->is_vcf) return 0;
+       if (!bp->is_vcf) return bcf_hdr_read(bp);
        h = calloc(1, sizeof(bcf_hdr_t));
        v = (vcf_t*)bp->v;
        v->line.l = 0;
@@ -35,15 +35,12 @@ bcf_hdr_t *vcf_hdr_read(bcf_t *bp)
                        kputsn(v->line.s, v->line.l, &meta); kputc('\n', &meta);
                } else if (v->line.s[0] == '#') {
                        int k;
-                       char *p, *q, *r;
-                       for (q = v->line.s, p = q + 1, k = 0; *p; ++p) {
-                               if (*p == '\t' || *(p+1) == 0) {
-                                       r = *(p+1) == 0? p+1 : p;
-                                       if (k >= 9) {
-                                               kputsn(q, r - q, &smpl);
-                                               kputc('\0', &smpl);
-                                       }
-                                       q = p + 1; ++k;
+                       ks_tokaux_t aux;
+                       char *p;
+                       for (p = kstrtok(v->line.s, "\t\n", &aux), k = 0; p; p = kstrtok(0, 0, &aux), ++k) {
+                               if (k >= 9) {
+                                       kputsn(p, aux.p - p, &smpl);
+                                       kputc('\0', &smpl);
                                }
                        }
                        break;
@@ -61,25 +58,25 @@ bcf_t *vcf_open(const char *fn, const char *mode)
 {
        bcf_t *bp;
        vcf_t *v;
+       if (strchr(mode, 'b')) return bcf_open(fn, mode);
        bp = calloc(1, sizeof(bcf_t));
        v = calloc(1, sizeof(vcf_t));
        bp->is_vcf = 1;
        bp->v = v;
+       v->refhash = bcf_str2id_init();
        if (strchr(mode, 'r')) {
                v->fp = strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(fileno(stdin), "r");
                v->ks = ks_init(v->fp);
        } else if (strchr(mode, 'w'))
-               v->fpout = strcmp(fn, "-")? fopen(fn, "w") : fdopen(fileno(stdout), "w");
+               v->fpout = strcmp(fn, "-")? fopen(fn, "w") : stdout;
        return bp;
 }
 
-void bcf_hdr_clear(bcf_hdr_t *b);
-
 int vcf_close(bcf_t *bp)
 {
        vcf_t *v;
        if (bp == 0) return -1;
-       if (bp->v == 0) return -1;
+       if (!bp->is_vcf) return bcf_close(bp);
        v = (vcf_t*)bp->v;
        if (v->fp) {
                ks_destroy(v->ks);
@@ -87,6 +84,7 @@ int vcf_close(bcf_t *bp)
        }
        if (v->fpout) fclose(v->fpout);
        free(v->line.s);
+       bcf_str2id_destroy(v->refhash);
        free(v);
        free(bp);
        return 0;
@@ -96,52 +94,73 @@ int vcf_hdr_write(bcf_t *bp, const bcf_hdr_t *h)
 {
        vcf_t *v = (vcf_t*)bp->v;
        int i;
-       if (v == 0 || v->fpout == 0) return -1;
-       fwrite(h->txt, 1, h->l_txt, v->fpout);
-       fprintf(v->fpout, "#CHROM\tPOS\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT");
+       if (!bp->is_vcf) return bcf_hdr_write(bp, h);
+       if (h->l_txt > 0) fwrite(h->txt, 1, h->l_txt - 1, v->fpout);
+       fprintf(v->fpout, "#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\tFORMAT");
        for (i = 0; i < h->n_smpl; ++i)
                fprintf(v->fpout, "\t%s", h->sns[i]);
        fputc('\n', v->fpout);
        return 0;
 }
 
+int vcf_write(bcf_t *bp, bcf_hdr_t *h, bcf1_t *b)
+{
+       vcf_t *v = (vcf_t*)bp->v;
+       extern void bcf_fmt_core(const bcf_hdr_t *h, bcf1_t *b, kstring_t *s);
+       if (!bp->is_vcf) return bcf_write(bp, h, b);
+       bcf_fmt_core(h, b, &v->line);
+       fwrite(v->line.s, 1, v->line.l, v->fpout);
+       fputc('\n', v->fpout);
+       return v->line.l + 1;
+}
+
 int vcf_read(bcf_t *bp, bcf_hdr_t *h, bcf1_t *b)
 {
-       int dret, k;
+       int dret, k, i, sync = 0;
        vcf_t *v = (vcf_t*)bp->v;
-       char *p, *q, *r;
-       kstring_t str;
+       char *p, *q;
+       kstring_t str, rn;
+       ks_tokaux_t aux, a2;
+       if (!bp->is_vcf) return bcf_read(bp, h, b);
        v->line.l = 0;
        str.l = 0; str.m = b->m_str; str.s = b->str;
+       rn.l = rn.m = h->l_nm; rn.s = h->name;
        if (ks_getuntil(v->ks, '\n', &v->line, &dret) < 0) return -1;
-       for (q = v->line.s, p = q + 1, k = 0; *p; ++p) {
-               if (*p == '\t' || *(p+1) == '\0') {
-                       ++k;
-                       r = *(p+1)? p : p + 1;
-                       *r = '\0';
-                       if (k == 1) { // ref
-                       } else if (k == 2) {
-                               b->pos = atoi(q);
-                       } else if (k == 3 || k == 4 || k == 5 || k == 7 || k == 8 || k == 9) {
-                               kputsn(q, r - q + 1, &str);
-                               if (k == 9) bcf_sync(h->n_smpl, b);
-                       } else if (k == 6) {
-                               b->qual = (q[0] >= '0' && q[0] <= '9')? atoi(q) : 0;
+       for (p = kstrtok(v->line.s, "\t", &aux), k = 0; p; p = kstrtok(0, 0, &aux), ++k) {
+               *(char*)aux.p = 0;
+               if (k == 0) { // ref
+                       int tid = bcf_str2id(v->refhash, p);
+                       if (tid < 0) {
+                               tid = bcf_str2id_add(v->refhash, p);
+                               kputs(p, &rn);
+                               sync = 1;
+                       }
+                       b->tid = tid;
+               } else if (k == 1) { // pos
+                       b->pos = atoi(p);
+               } else if (k == 5) { // qual
+                       b->qual = (p[0] >= '0' && p[0] <= '9')? atoi(p) : 0;
+               } else if (k <= 8) { // variable length strings
+                       kputs(p, &str); kputc('\0', &str);
+                       b->l_str = str.l; b->m_str = str.m; b->str = str.s;
+                       if (k == 8) bcf_sync(h->n_smpl, b);
+               } else {
+                       for (q = kstrtok(p, ":", &a2), i = 0; q && i < b->n_gi; q = kstrtok(0, 0, &a2), ++i) {
+                               if (b->gi[i].fmt == bcf_str2int("GT", 2)) {
+                                       ((uint8_t*)b->gi[i].data)[k-9] = (q[0] - '0')<<3 | (q[2] - '0') | (q[1] == '/'? 0 : 1) << 6;
+                               } else if (b->gi[i].fmt == bcf_str2int("GQ", 2)) {
+                                       int x = strtol(q, &q, 10);
+                                       if (x > 255) x = 255;
+                                       ((uint8_t*)b->gi[i].data)[k-9] = x;
+                               } else if (b->gi[i].fmt == bcf_str2int("DP", 2)) {
+                                       int x = strtol(q, &q, 10);
+                                       if (x > 0xffff) x = 0xffff;
+                                       ((uint16_t*)b->gi[i].data)[k-9] = x;
+                               }
                        }
-                       q = p + 1;
                }
        }
+       h->l_nm = rn.l; h->name = rn.s;
+       if (sync) bcf_hdr_sync(h);
        return v->line.l + 1;
 }
-
-int vcf_test(int argc, char *argv[])
-{
-       bcf_t *bp, *bpout;
-       bcf_hdr_t *h;
-       bp = vcf_open(argv[1], "r");
-       bpout = vcf_open("-", "w");
-       h = vcf_hdr_read(bpout);
-       vcf_hdr_write(bpout, h);
-       vcf_close(bp);
-       return 0;
-}
index dfcb25a4c0a40cadda0cadf1c702545e0aa1a01b..58f11a2e8499ec9f0e888feae7c8aaba6543dfa1 100644 (file)
@@ -15,9 +15,11 @@ KSTREAM_INIT(gzFile, gzread, 16384)
 
 #define VC_NO_PL   1
 #define VC_NO_GENO 2
-#define VC_BCF     4
+#define VC_BCFOUT  4
 #define VC_CALL    8
 #define VC_VARONLY 16
+#define VC_VCFIN   32
+#define VC_UNCOMP  64
 
 typedef struct {
        int flag, prior_type;
@@ -149,19 +151,22 @@ int bcfview(int argc, char *argv[])
        bcf_p1aux_t *p1 = 0;
        bcf_hdr_t *h;
        int tid, begin, end;
+       char moder[4], modew[4];
        khash_t(set64) *hash = 0;
 
        tid = begin = end = -1;
        memset(&vc, 0, sizeof(viewconf_t));
        vc.prior_type = -1; vc.theta = 1e-3; vc.pref = 0.9;
-       while ((c = getopt(argc, argv, "l:cGvLbP:t:p:")) >= 0) {
+       while ((c = getopt(argc, argv, "l:cGvLbSuP:t:p:")) >= 0) {
                switch (c) {
                case 'l': vc.fn_list = strdup(optarg); break;
                case 'G': vc.flag |= VC_NO_GENO; break;
                case 'L': vc.flag |= VC_NO_PL; break;
-               case 'b': vc.flag |= VC_BCF; break;
+               case 'b': vc.flag |= VC_BCFOUT; break;
+               case 'S': vc.flag |= VC_VCFIN; break;
                case 'c': vc.flag |= VC_CALL; break;
                case 'v': vc.flag |= VC_VARONLY; break;
+               case 'u': vc.flag |= VC_UNCOMP | VC_BCFOUT; break;
                case 't': vc.theta = atof(optarg); break;
                case 'p': vc.pref = atof(optarg); break;
                case 'P':
@@ -176,6 +181,8 @@ int bcfview(int argc, char *argv[])
                fprintf(stderr, "Usage:   bcftools view [options] <in.bcf> [reg]\n\n");
                fprintf(stderr, "Options: -c        SNP calling\n");
                fprintf(stderr, "         -b        output BCF instead of VCF\n");
+               fprintf(stderr, "         -u        uncompressed BCF output\n");
+               fprintf(stderr, "         -S        input is VCF\n");
                fprintf(stderr, "         -G        suppress all individual genotype information\n");
                fprintf(stderr, "         -L        discard the PL genotype field\n");
                fprintf(stderr, "         -v        output potential variant sites only\n");
@@ -188,18 +195,21 @@ int bcfview(int argc, char *argv[])
        }
 
        b = calloc(1, sizeof(bcf1_t));
-       bp = bcf_open(argv[optind], "r");
-       h = bcf_hdr_read(bp);
-       if (vc.flag & VC_BCF) {
-               bout = bcf_open("-", "w");
-               bcf_hdr_write(bout, h);
-       }
+       strcpy(moder, "r");
+       if (!(vc.flag & VC_VCFIN)) strcat(moder, "b");
+       strcpy(modew, "w");
+       if (vc.flag & VC_BCFOUT) strcat(modew, "b");
+       if (vc.flag & VC_UNCOMP) strcat(modew, "u");
+       bp = vcf_open(argv[optind], moder);
+       h = vcf_hdr_read(bp);
+       bout = vcf_open("-", modew);
+       vcf_hdr_write(bout, h);
        if (vc.flag & VC_CALL) {
                p1 = bcf_p1_init(h->n_smpl);
                bcf_p1_init_prior(p1, vc.prior_type, vc.theta);
        }
        if (vc.fn_list) hash = bcf_load_pos(vc.fn_list, h);
-       if (optind + 1 < argc) {
+       if (optind + 1 < argc && !(vc.flag&VC_VCFIN)) {
                void *str2id = bcf_build_refhash(h);
                if (bcf_parse_region(str2id, argv[optind+1], &tid, &begin, &end) >= 0) {
                        bcf_idx_t *idx;
@@ -212,7 +222,7 @@ int bcfview(int argc, char *argv[])
                        }
                }
        }
-       while (bcf_read(bp, h, b) > 0) {
+       while (vcf_read(bp, h, b) > 0) {
                if (hash) {
                        uint64_t x = (uint64_t)b->tid<<32 | b->pos;
                        khint_t k = kh_get(set64, hash, x);
@@ -231,23 +241,17 @@ int bcfview(int argc, char *argv[])
                        if (pr.p_ref >= vc.pref && (vc.flag & VC_VARONLY)) continue;
                        update_bcf1(h->n_smpl, b, p1, &pr, vc.pref, vc.flag);
                }
-               if (vc.flag & VC_BCF) bcf_write(bout, h, b);
-               else {
-                       char *vcf;
-                       if (vc.flag & VC_NO_GENO) {
-                               b->n_gi = 0;
-                               b->fmt[0] = '\0';
-                       }
-                       vcf = bcf_fmt(h, b);
-                       puts(vcf);
-                       free(vcf);
+               if (vc.flag & VC_NO_GENO) {
+                       b->n_gi = 0;
+                       b->fmt[0] = '\0';
                }
+               vcf_write(bout, h, b);
                ++n_processed;
        }
        if (vc.flag & VC_CALL) bcf_p1_dump_afs(p1);
        bcf_hdr_destroy(h);
-       bcf_close(bp); bcf_close(bout);
        bcf_destroy(b);
+       vcf_close(bp); vcf_close(bout);
        if (hash) kh_destroy(set64, hash);
        if (vc.fn_list) free(vc.fn_list);
        if (p1) bcf_p1_destroy(p1);
diff --git a/bgzf.c b/bgzf.c
index a6923daa0cc1cfa8d0d0bc2269255326be8439e3..66d6b024f5441f694faf1d875febe9fe8e3c248c 100644 (file)
--- a/bgzf.c
+++ b/bgzf.c
@@ -177,7 +177,7 @@ BGZF*
 bgzf_open(const char* __restrict path, const char* __restrict mode)
 {
     BGZF* fp = NULL;
-    if (mode[0] == 'r' || mode[0] == 'R') { /* The reading mode is preferred. */
+    if (strchr(mode, 'r') || strchr(mode, 'R')) { /* The reading mode is preferred. */
 #ifdef _USE_KNETFILE
                knetFile *file = knet_open(path, mode);
                if (file == 0) return 0;
@@ -194,14 +194,14 @@ bgzf_open(const char* __restrict path, const char* __restrict mode)
                if (fd == -1) return 0;
         fp = open_read(fd);
 #endif
-    } else if (mode[0] == 'w' || mode[0] == 'W') {
+    } else if (strchr(mode, 'w') || strchr(mode, 'W')) {
                int fd, oflag = O_WRONLY | O_CREAT | O_TRUNC;
 #ifdef _WIN32
                oflag |= O_BINARY;
 #endif
                fd = open(path, oflag, 0666);
                if (fd == -1) return 0;
-        fp = open_write(fd, strstr(mode, "u")? 1 : 0);
+        fp = open_write(fd, strchr(mode, 'u')? 1 : 0);
     }
     if (fp != NULL) fp->owned_file = 1;
     return fp;
index a09180bde9fe38fe7f7fe255de1708f22c3945b7..43d524c92efc38fb7d417759aa4caaabf402aa05 100644 (file)
--- a/kstring.c
+++ b/kstring.c
@@ -36,7 +36,7 @@ char *kstrtok(const char *str, const char *sep, ks_tokaux_t *aux)
        if (str) aux->p = str - 1, aux->tab[0] &= ~1ull;
        else if (aux->tab[0]&1) return 0;
        for (p = start = aux->p + 1; *p; ++p)
-               if (aux->tab[*p/64]>>(*p%64)) break;
+               if (aux->tab[*p/64]>>(*p%64)&1) break;
        aux->p = p; // end of token
        if (*p == 0) aux->tab[0] |= 1; // no more tokens
        return (char*)start;