let parse_cigar text =
  match text with
  | "*" -> Ok []
  | "" ->
    error "invalid cigar string" text sexp_of_string
  | _ ->
    let ch = Scanf.Scanning.from_string text in
    let rec loop accum =
      if Scanf.Scanning.end_of_input ch then Ok accum
      else
        try
          let n = Scanf.bscanf ch "%d" ident in
          let c = Scanf.bscanf ch "%c" ident in
          let x =
            match c with
            | 'M' -> cigar_op_alignment_match n
            | 'I' -> cigar_op_insertion n
            | 'D' -> cigar_op_deletion n
            | 'N' -> cigar_op_skipped n
            | 'S' -> cigar_op_soft_clipping n
            | 'H' -> cigar_op_hard_clipping n
            | 'P' -> cigar_op_padding n
            | '=' -> cigar_op_seq_match n
            | 'X' -> cigar_op_seq_mismatch n
            | other -> Or_error.error_string "invalid cigar operation type"
          in
          Or_error.tag x "Sam.parse_cigar: invalid cigar string" >>= fun x ->
          loop (x::accum)
        with
          _ ->
            error "invalid cigar string" text sexp_of_string
    in
    loop [] >>| List.rev