- uint32_t x = c->pos, y = 0;
- int ret = 1, is_restart = 1;
-
- if (c->flag&BAM_FUNMAP) return 0; // unmapped read
- assert(x <= pos); // otherwise a bug
- p->qpos = -1; p->indel = 0; p->is_del = p->is_head = p->is_tail = 0;
- for (k = 0; k < c->n_cigar; ++k) {
- int op = bam1_cigar(b)[k] & BAM_CIGAR_MASK; // operation
- int l = bam1_cigar(b)[k] >> BAM_CIGAR_SHIFT; // length
- if (op == BAM_CMATCH) { // NOTE: this assumes the first and the last operation MUST BE a match or a clip
- if (x + l > pos) { // overlap with pos
- p->indel = p->is_del = 0;
- p->qpos = y + (pos - x);
- if (x == pos && is_restart) p->is_head = 1;
- if (x + l - 1 == pos) { // come to the end of a match
- int has_next_match = 0;
- unsigned i;
- for (i = k + 1; i < c->n_cigar; ++i) {
- uint32_t cigar = bam1_cigar(b)[i];
- int opi = cigar&BAM_CIGAR_MASK;
- if (opi == BAM_CMATCH) {
- has_next_match = 1;
- break;
- } else if (opi == BAM_CSOFT_CLIP || opi == BAM_CREF_SKIP || opi == BAM_CHARD_CLIP) break;
- }
- if (!has_next_match) p->is_tail = 1;
- if (k < c->n_cigar - 1 && has_next_match) { // there are additional operation(s)
- uint32_t cigar = bam1_cigar(b)[k+1]; // next CIGAR
- int op_next = cigar&BAM_CIGAR_MASK; // next CIGAR operation
- if (op_next == BAM_CDEL) p->indel = -(int32_t)(cigar>>BAM_CIGAR_SHIFT); // del
- else if (op_next == BAM_CINS) p->indel = cigar>>BAM_CIGAR_SHIFT; // ins
- else if (op_next == BAM_CPAD && k + 2 < c->n_cigar) { // no working for adjacent padding
- cigar = bam1_cigar(b)[k+2]; op_next = cigar&BAM_CIGAR_MASK;
- if (op_next == BAM_CDEL) p->indel = -(int32_t)(cigar>>BAM_CIGAR_SHIFT); // del
- else if (op_next == BAM_CINS) p->indel = cigar>>BAM_CIGAR_SHIFT; // ins
- }
- }
+ uint32_t *cigar = bam1_cigar(b);
+ int k, is_head = 0;
+ // determine the current CIGAR operation
+// fprintf(stderr, "%s\tpos=%d\tend=%d\t(%d,%d,%d)\n", bam1_qname(b), pos, s->end, s->k, s->x, s->y);
+ if (s->k == -1) { // never processed
+ is_head = 1;
+ if (c->n_cigar == 1) { // just one operation, save a loop
+ if (_cop(cigar[0]) == BAM_CMATCH || _cop(cigar[0]) == BAM_CEQUAL || _cop(cigar[0]) == BAM_CDIFF) s->k = 0, s->x = c->pos, s->y = 0;
+ } else { // find the first match or deletion
+ for (k = 0, s->x = c->pos, s->y = 0; k < c->n_cigar; ++k) {
+ int op = _cop(cigar[k]);
+ int l = _cln(cigar[k]);
+ if (op == BAM_CMATCH || op == BAM_CDEL || op == BAM_CEQUAL || op == BAM_CDIFF) break;
+ else if (op == BAM_CREF_SKIP) s->x += l;
+ else if (op == BAM_CINS || op == BAM_CSOFT_CLIP) s->y += l;
+ }
+ assert(k < c->n_cigar);
+ s->k = k;
+ }
+ } else { // the read has been processed before
+ int op, l = _cln(cigar[s->k]);
+ if (pos - s->x >= l) { // jump to the next operation
+ assert(s->k < c->n_cigar); // otherwise a bug: this function should not be called in this case
+ op = _cop(cigar[s->k+1]);
+ if (op == BAM_CMATCH || op == BAM_CDEL || op == BAM_CREF_SKIP || op == BAM_CEQUAL || op == BAM_CDIFF) { // jump to the next without a loop
+ if (_cop(cigar[s->k]) == BAM_CMATCH|| _cop(cigar[s->k]) == BAM_CEQUAL || _cop(cigar[s->k]) == BAM_CDIFF) s->y += l;
+ s->x += l;
+ ++s->k;
+ } else { // find the next M/D/N/=/X
+ if (_cop(cigar[s->k]) == BAM_CMATCH|| _cop(cigar[s->k]) == BAM_CEQUAL || _cop(cigar[s->k]) == BAM_CDIFF) s->y += l;
+ s->x += l;
+ for (k = s->k + 1; k < c->n_cigar; ++k) {
+ op = _cop(cigar[k]), l = _cln(cigar[k]);
+ if (op == BAM_CMATCH || op == BAM_CDEL || op == BAM_CREF_SKIP || op == BAM_CEQUAL || op == BAM_CDIFF) break;
+ else if (op == BAM_CINS || op == BAM_CSOFT_CLIP) s->y += l;