+bam_plp_t bam_plp_init(bam_plp_auto_f func, void *data)
+{
+ bam_plp_t iter;
+ iter = calloc(1, sizeof(struct __bam_plp_t));
+ iter->mp = mp_init();
+ iter->head = iter->tail = mp_alloc(iter->mp);
+ iter->dummy = mp_alloc(iter->mp);
+ iter->max_tid = iter->max_pos = -1;
+ iter->flag_mask = BAM_DEF_MASK;
+ iter->maxcnt = 8000;
+ if (func) {
+ iter->func = func;
+ iter->data = data;
+ iter->b = bam_init1();
+ }
+ return iter;
+}
+
+void bam_plp_destroy(bam_plp_t iter)
+{
+ mp_free(iter->mp, iter->dummy);
+ mp_free(iter->mp, iter->head);
+ if (iter->mp->cnt != 0)
+ fprintf(stderr, "[bam_plp_destroy] memory leak: %d. Continue anyway.\n", iter->mp->cnt);
+ mp_destroy(iter->mp);
+ if (iter->b) bam_destroy1(iter->b);
+ free(iter->plp);
+ free(iter);
+}
+
+const bam_pileup1_t *bam_plp_next(bam_plp_t iter, int *_tid, int *_pos, int *_n_plp)
+{
+ if (iter->error) { *_n_plp = -1; return 0; }
+ *_n_plp = 0;
+ if (iter->is_eof && iter->head->next == 0) return 0;
+ while (iter->is_eof || iter->max_tid > iter->tid || (iter->max_tid == iter->tid && iter->max_pos > iter->pos)) {
+ int n_plp = 0;
+ lbnode_t *p, *q;
+ // write iter->plp at iter->pos
+ iter->dummy->next = iter->head;
+ for (p = iter->head, q = iter->dummy; p->next; q = p, p = p->next) {
+ if (p->b.core.tid < iter->tid || (p->b.core.tid == iter->tid && p->end <= iter->pos)) { // then remove
+ q->next = p->next; mp_free(iter->mp, p); p = q;
+ } else if (p->b.core.tid == iter->tid && p->beg <= iter->pos) { // here: p->end > pos; then add to pileup
+ if (n_plp == iter->max_plp) { // then double the capacity
+ iter->max_plp = iter->max_plp? iter->max_plp<<1 : 256;
+ iter->plp = (bam_pileup1_t*)realloc(iter->plp, sizeof(bam_pileup1_t) * iter->max_plp);
+ }
+ iter->plp[n_plp].b = &p->b;
+ if (resolve_cigar2(iter->plp + n_plp, iter->pos, &p->s)) ++n_plp; // actually always true...
+ }
+ }
+ iter->head = iter->dummy->next; // dummy->next may be changed
+ *_n_plp = n_plp; *_tid = iter->tid; *_pos = iter->pos;
+ // update iter->tid and iter->pos
+ if (iter->head->next) {
+ if (iter->tid > iter->head->b.core.tid) {
+ fprintf(stderr, "[%s] unsorted input. Pileup aborts.\n", __func__);
+ iter->error = 1;
+ *_n_plp = -1;
+ return 0;
+ }
+ }
+ if (iter->tid < iter->head->b.core.tid) { // come to a new reference sequence
+ iter->tid = iter->head->b.core.tid; iter->pos = iter->head->beg; // jump to the next reference
+ } else if (iter->pos < iter->head->beg) { // here: tid == head->b.core.tid
+ iter->pos = iter->head->beg; // jump to the next position
+ } else ++iter->pos; // scan contiguously
+ // return
+ if (n_plp) return iter->plp;
+ if (iter->is_eof && iter->head->next == 0) break;
+ }
+ return 0;
+}
+
+int bam_plp_push(bam_plp_t iter, const bam1_t *b)
+{
+ if (iter->error) return -1;
+ if (b) {
+ if (b->core.tid < 0) return 0;
+ if (b->core.flag & iter->flag_mask) return 0;
+ if (iter->tid == b->core.tid && iter->pos == b->core.pos && iter->mp->cnt > iter->maxcnt) return 0;
+ bam_copy1(&iter->tail->b, b);
+ iter->tail->beg = b->core.pos; iter->tail->end = bam_calend(&b->core, bam1_cigar(b));
+ iter->tail->s = g_cstate_null; iter->tail->s.end = iter->tail->end - 1; // initialize cstate_t
+ if (b->core.tid < iter->max_tid) {
+ fprintf(stderr, "[bam_pileup_core] the input is not sorted (chromosomes out of order)\n");
+ iter->error = 1;
+ return -1;
+ }
+ if ((b->core.tid == iter->max_tid) && (iter->tail->beg < iter->max_pos)) {
+ fprintf(stderr, "[bam_pileup_core] the input is not sorted (reads out of order)\n");
+ iter->error = 1;
+ return -1;
+ }
+ iter->max_tid = b->core.tid; iter->max_pos = iter->tail->beg;
+ if (iter->tail->end > iter->pos || iter->tail->b.core.tid > iter->tid) {
+ iter->tail->next = mp_alloc(iter->mp);
+ iter->tail = iter->tail->next;
+ }
+ } else iter->is_eof = 1;
+ return 0;
+}
+
+const bam_pileup1_t *bam_plp_auto(bam_plp_t iter, int *_tid, int *_pos, int *_n_plp)
+{
+ const bam_pileup1_t *plp;
+ if (iter->func == 0 || iter->error) { *_n_plp = -1; return 0; }
+ if ((plp = bam_plp_next(iter, _tid, _pos, _n_plp)) != 0) return plp;
+ else { // no pileup line can be obtained; read alignments
+ *_n_plp = 0;
+ if (iter->is_eof) return 0;
+ while (iter->func(iter->data, iter->b) >= 0) {
+ if (bam_plp_push(iter, iter->b) < 0) {
+ *_n_plp = -1;
+ return 0;
+ }
+ if ((plp = bam_plp_next(iter, _tid, _pos, _n_plp)) != 0) return plp;
+ // otherwise no pileup line can be returned; read the next alignment.
+ }
+ bam_plp_push(iter, 0);
+ if ((plp = bam_plp_next(iter, _tid, _pos, _n_plp)) != 0) return plp;
+ return 0;
+ }
+}
+
+void bam_plp_reset(bam_plp_t iter)