static int bed_rest(GtBEDParser *bed_parser, GtIO *bed_file, GtError *err) { GtUword block_count = 0; GtGenomeNode *gn = NULL; GtRange range; GtStr *seqid; int had_err; gt_error_check(err); /* column 1.: chrom */ seqid = get_seqid(bed_parser); had_err = skip_blanks(bed_file, err); /* column 2.: chromStart */ if (!had_err) { word(bed_parser->word, bed_file); had_err = skip_blanks(bed_file, err); } /* column 3.: chromEnd */ if (!had_err) { word(bed_parser->another_word, bed_file); had_err = parse_bed_range(&range, bed_parser->word, bed_parser->another_word, bed_parser->offset, bed_file, false, err); } if (!had_err) { /* add region */ gt_region_node_builder_add_region(bed_parser->region_node_builder, gt_str_get(seqid), range); /* create feature */ gn = gt_feature_node_new(seqid, bed_parser->feature_type ? bed_parser->feature_type : BED_FEATURE_TYPE, range.start, range.end, GT_STRAND_BOTH); gt_queue_add(bed_parser->feature_nodes, gn); if (bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); } /* optional column 4.: name */ if (!had_err) { word(bed_parser->word, bed_file); if (gt_str_length(bed_parser->word)) { gt_feature_node_add_attribute((GtFeatureNode*) gn, GT_GFF_NAME, gt_str_get(bed_parser->word)); } if (bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); } /* optional column 5.: score */ if (!had_err) { word(bed_parser->word, bed_file); if (gt_str_length(bed_parser->word)) { bool score_is_defined; float score_value; had_err = gt_parse_score(&score_is_defined, &score_value, gt_str_get(bed_parser->word), gt_io_get_line_number(bed_file), gt_io_get_filename(bed_file), err); if (!had_err && score_is_defined) gt_feature_node_set_score((GtFeatureNode*) gn, score_value); } } if (!had_err && bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); /* optional column 6.: strand */ if (!had_err) { word(bed_parser->word, bed_file); if (gt_str_length(bed_parser->word)) { GtStrand strand; had_err = gt_parse_strand(&strand, gt_str_get(bed_parser->word), gt_io_get_line_number(bed_file), gt_io_get_filename(bed_file), err); if (!had_err) gt_feature_node_set_strand((GtFeatureNode*) gn, strand); } } if (!had_err && bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); /* optional column 7.: thickStart */ if (!had_err) { word(bed_parser->word, bed_file); if (bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); } /* optional column 8.: thickEnd */ if (!had_err) { word(bed_parser->another_word, bed_file); if (gt_str_length(bed_parser->another_word)) { gt_assert(gt_str_length(bed_parser->word)); /* got a thickStart and a thickEnd -> construct corresponding feature */ had_err = parse_bed_range(&range, bed_parser->word, bed_parser->another_word, bed_parser->offset, bed_file, true, err); if (!had_err && range.start <= range.end) construct_thick_feature(bed_parser, (GtFeatureNode*) gn, range); } } if (!had_err && bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); /* optional column 9.: itemRgb */ if (!had_err) { word(bed_parser->word, bed_file); /* we do not use the RGB values */ if (bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); } /* optional column 10.: blockCount */ if (!had_err) { word(bed_parser->word, bed_file); if (gt_str_length(bed_parser->word)) { if (gt_parse_uword(&block_count, gt_str_get(bed_parser->word))) { gt_error_set(err, "file \"%s\": line "GT_WU": could not parse blockCount", gt_io_get_filename(bed_file), gt_io_get_line_number(bed_file)); had_err = -1; } else { /* reset to parse/process blockSizes and blockStarts properly */ gt_str_reset(bed_parser->word); gt_str_reset(bed_parser->another_word); } } } if (!had_err && bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); /* optional column 11.: blockSizes */ if (!had_err) { word(bed_parser->word, bed_file); if (bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); } /* optional column 12.: blockStarts */ if (!had_err) { word(bed_parser->another_word, bed_file); if (bed_separator(bed_file)) had_err = skip_blanks(bed_file, err); } /* process blocks if necessary */ if (!had_err && block_count) { had_err = process_blocks(bed_parser, (GtFeatureNode*) gn, block_count, bed_parser->word, bed_parser->another_word, bed_file, err); } /* the end of the line should now be reached */ if (!had_err) had_err = gt_io_expect(bed_file, GT_END_OF_LINE, err); return had_err; }
int gt_gtf_parser_parse(GtGTFParser *parser, GtQueue *genome_nodes, GtStr *filenamestr, GtFile *fpin, bool be_tolerant, GtError *err) { GtStr *seqid_str, *source_str, *line_buffer; char *line; size_t line_length; GtUword i, line_number = 0; GtGenomeNode *gn; GtRange range; GtPhase phase_value; GtStrand gt_strand_value; GtSplitter *splitter, *attribute_splitter; float score_value; char *seqname, *source, *feature, *start, *end, *score, *strand, *frame, *attributes, *token, *gene_id, *gene_name = NULL, *transcript_id, *transcript_name = NULL, **tokens; GtHashmap *transcript_id_hash; /* map from transcript id to array of genome nodes */ GtArray *gt_genome_node_array; ConstructionInfo cinfo; GTF_feature_type gtf_feature_type; GT_UNUSED bool gff_type_is_valid = false; const char *type = NULL; const char *filename; bool score_is_defined; int had_err = 0; gt_assert(parser && genome_nodes); gt_error_check(err); filename = gt_str_get(filenamestr); /* alloc */ line_buffer = gt_str_new(); splitter = gt_splitter_new(), attribute_splitter = gt_splitter_new(); #define HANDLE_ERROR \ if (had_err) { \ if (be_tolerant) { \ fprintf(stderr, "skipping line: %s\n", gt_error_get(err)); \ gt_error_unset(err); \ gt_str_reset(line_buffer); \ had_err = 0; \ continue; \ } \ else { \ had_err = -1; \ break; \ } \ } while (gt_str_read_next_line_generic(line_buffer, fpin) != EOF) { line = gt_str_get(line_buffer); line_length = gt_str_length(line_buffer); line_number++; had_err = 0; if (line_length == 0) { gt_warning("skipping blank line " GT_WU " in file \"%s\"", line_number, filename); } else if (line[0] == '#') { /* storing comment */ if (line_length >= 2 && line[1] == '#') gn = gt_comment_node_new(line+2); /* store '##' line as '#' line */ else gn = gt_comment_node_new(line+1); gt_genome_node_set_origin(gn, filenamestr, line_number); gt_queue_add(genome_nodes, gn); } else { /* process tab delimited GTF line */ gt_splitter_reset(splitter); gt_splitter_split(splitter, line, line_length, '\t'); if (gt_splitter_size(splitter) != 9UL) { gt_error_set(err, "line " GT_WU " in file \"%s\" contains " GT_WU " tab (\\t) " "separated fields instead of 9", line_number, filename, gt_splitter_size(splitter)); had_err = -1; break; } tokens = gt_splitter_get_tokens(splitter); seqname = tokens[0]; source = tokens[1]; feature = tokens[2]; start = tokens[3]; end = tokens[4]; score = tokens[5]; strand = tokens[6]; frame = tokens[7]; attributes = tokens[8]; /* parse feature */ if (GTF_feature_type_get(>f_feature_type, feature) == -1) { /* we skip unknown features */ fprintf(stderr, "skipping line " GT_WU " in file \"%s\": unknown " "feature: \"%s\"\n", line_number, filename, feature); gt_str_reset(line_buffer); continue; } /* translate into GFF3 feature type */ switch (gtf_feature_type) { case GTF_CDS: case GTF_stop_codon: gff_type_is_valid = gt_type_checker_is_valid(parser->type_checker, gt_ft_CDS); type = gt_ft_CDS; break; case GTF_exon: gff_type_is_valid = gt_type_checker_is_valid(parser->type_checker, gt_ft_exon); type = gt_ft_exon; } gt_assert(gff_type_is_valid); /* parse the range */ had_err = gt_parse_range(&range, start, end, line_number, filename, err); HANDLE_ERROR; /* process seqname (we have to do it here because we need the range) */ gt_region_node_builder_add_region(parser->region_node_builder, seqname, range); /* parse the score */ had_err = gt_parse_score(&score_is_defined, &score_value, score, line_number, filename, err); HANDLE_ERROR; /* parse the strand */ had_err = gt_parse_strand(>_strand_value, strand, line_number, filename, err); HANDLE_ERROR; /* parse the frame */ had_err = gt_parse_phase(&phase_value, frame, line_number, filename, err); HANDLE_ERROR; /* parse the attributes */ gt_splitter_reset(attribute_splitter); gene_id = NULL; transcript_id = NULL; gt_splitter_split(attribute_splitter, attributes, strlen(attributes), ';'); for (i = 0; i < gt_splitter_size(attribute_splitter); i++) { token = gt_splitter_get_token(attribute_splitter, i); /* skip leading blanks */ while (*token == ' ') token++; /* look for the two mandatory attributes */ if (strncmp(token, GENE_ID_ATTRIBUTE, strlen(GENE_ID_ATTRIBUTE)) == 0) { if (strlen(token) + 2 < strlen(GENE_ID_ATTRIBUTE)) { gt_error_set(err, "missing value to attribute \"%s\" on line " GT_WU "in file \"%s\"", GENE_ID_ATTRIBUTE, line_number, filename); had_err = -1; } HANDLE_ERROR; gene_id = token + strlen(GENE_ID_ATTRIBUTE) + 1; } else if (strncmp(token, TRANSCRIPT_ID_ATTRIBUTE, strlen(TRANSCRIPT_ID_ATTRIBUTE)) == 0) { if (strlen(token) + 2 < strlen(TRANSCRIPT_ID_ATTRIBUTE)) { gt_error_set(err, "missing value to attribute \"%s\" on line " GT_WU "in file \"%s\"", TRANSCRIPT_ID_ATTRIBUTE, line_number, filename); had_err = -1; } HANDLE_ERROR; transcript_id = token + strlen(TRANSCRIPT_ID_ATTRIBUTE) + 1; } else if (strncmp(token, GENE_NAME_ATTRIBUTE, strlen(GENE_NAME_ATTRIBUTE)) == 0) { if (strlen(token) + 2 < strlen(GENE_NAME_ATTRIBUTE)) { gt_error_set(err, "missing value to attribute \"%s\" on line " GT_WU "in file \"%s\"", GENE_NAME_ATTRIBUTE, line_number, filename); had_err = -1; } HANDLE_ERROR; gene_name = token + strlen(GENE_NAME_ATTRIBUTE) + 1; /* for output we want to strip quotes */ if (*gene_name == '"') gene_name++; if (gene_name[strlen(gene_name)-1] == '"') gene_name[strlen(gene_name)-1] = '\0'; } else if (strncmp(token, TRANSCRIPT_NAME_ATTRIBUTE, strlen(TRANSCRIPT_NAME_ATTRIBUTE)) == 0) { if (strlen(token) + 2 < strlen(TRANSCRIPT_NAME_ATTRIBUTE)) { gt_error_set(err, "missing value to attribute \"%s\" on line " GT_WU "in file \"%s\"", TRANSCRIPT_NAME_ATTRIBUTE, line_number, filename); had_err = -1; } HANDLE_ERROR; transcript_name = token + strlen(TRANSCRIPT_NAME_ATTRIBUTE) + 1; /* for output we want to strip quotes */ if (*transcript_name == '"') transcript_name++; if (transcript_name[strlen(transcript_name)-1] == '"') transcript_name[strlen(transcript_name)-1] = '\0'; } } /* check for the mandatory attributes */ if (!gene_id) { gt_error_set(err, "missing attribute \"%s\" on line " GT_WU " in file \"%s\"", GENE_ID_ATTRIBUTE, line_number, filename); had_err = -1; } HANDLE_ERROR; if (!transcript_id) { gt_error_set(err, "missing attribute \"%s\" on line " GT_WU " in file \"%s\"", TRANSCRIPT_ID_ATTRIBUTE, line_number, filename); had_err = -1; } HANDLE_ERROR; /* process the mandatory attributes */ if (!(transcript_id_hash = gt_hashmap_get(parser->gene_id_hash, gene_id))) { transcript_id_hash = gt_hashmap_new(GT_HASH_STRING, gt_free_func, (GtFree) gt_array_delete); gt_hashmap_add(parser->gene_id_hash, gt_cstr_dup(gene_id), transcript_id_hash); } gt_assert(transcript_id_hash); if (!(gt_genome_node_array = gt_hashmap_get(transcript_id_hash, transcript_id))) { gt_genome_node_array = gt_array_new(sizeof (GtGenomeNode*)); gt_hashmap_add(transcript_id_hash, gt_cstr_dup(transcript_id), gt_genome_node_array); } gt_assert(gt_genome_node_array); /* save optional gene_name and transcript_name attributes */ if (transcript_name && !gt_hashmap_get(parser->transcript_id_to_name_mapping, transcript_id)) { gt_hashmap_add(parser->transcript_id_to_name_mapping, gt_cstr_dup(transcript_id), gt_cstr_dup(transcript_name)); } if (gene_name && !gt_hashmap_get(parser->gene_id_to_name_mapping, gene_id)) { gt_hashmap_add(parser->gene_id_to_name_mapping, gt_cstr_dup(gene_id), gt_cstr_dup(gene_name)); } /* get seqid */ seqid_str = gt_hashmap_get(parser->seqid_to_str_mapping, seqname); if (!seqid_str) { seqid_str = gt_str_new_cstr(seqname); gt_hashmap_add(parser->seqid_to_str_mapping, gt_str_get(seqid_str), seqid_str); } gt_assert(seqid_str); /* construct the new feature */ gn = gt_feature_node_new(seqid_str, type, range.start, range.end, gt_strand_value); gt_genome_node_set_origin(gn, filenamestr, line_number); /* set source */ source_str = gt_hashmap_get(parser->source_to_str_mapping, source); if (!source_str) { source_str = gt_str_new_cstr(source); gt_hashmap_add(parser->source_to_str_mapping, gt_str_get(source_str), source_str); } gt_assert(source_str); gt_feature_node_set_source((GtFeatureNode*) gn, source_str); if (score_is_defined) gt_feature_node_set_score((GtFeatureNode*) gn, score_value); if (phase_value != GT_PHASE_UNDEFINED) gt_feature_node_set_phase((GtFeatureNode*) gn, phase_value); gt_array_add(gt_genome_node_array, gn); } gt_str_reset(line_buffer); } /* process all region nodes */ if (!had_err) gt_region_node_builder_build(parser->region_node_builder, genome_nodes); /* process all feature nodes */ cinfo.genome_nodes = genome_nodes; cinfo.gene_id_to_name_mapping = parser->gene_id_to_name_mapping; cinfo.transcript_id_to_name_mapping = parser->transcript_id_to_name_mapping; if (!had_err) { had_err = gt_hashmap_foreach(parser->gene_id_hash, construct_genes, &cinfo, err); } /* free */ gt_splitter_delete(splitter); gt_splitter_delete(attribute_splitter); gt_str_delete(line_buffer); return had_err; }