static int feature_index_lua_add_feature_node(lua_State *L) { GtFeatureIndex **fi; GtGenomeNode **gn; GtFeatureNode *fn; GtStr *seqid; GtError *err; bool has_seqid; gt_assert(L); fi = check_feature_index(L, 1); gn = check_genome_node(L, 2); fn = gt_feature_node_cast(*gn); luaL_argcheck(L, fn, 2, "not a feature node"); seqid = gt_genome_node_get_seqid(*gn); luaL_argcheck(L, seqid, 2, "feature does not have a sequence id"); err = gt_error_new(); if (gt_feature_index_has_seqid(*fi, &has_seqid, gt_str_get(seqid), err)) return gt_lua_error(L, err); gt_error_delete(err); luaL_argcheck(L, has_seqid, 2, "feature index does not contain corresponding sequence region"); err = gt_error_new(); if (gt_feature_index_add_feature_node(*fi, fn, err)) return gt_lua_error(L, err); gt_error_delete(err); return 0; }
static int feature_index_lua_get_features_for_range(lua_State *L) { GtFeatureIndex **feature_index; const char *seqid; GtRange *range; GtError *err; bool has_seqid; GtArray *features; GT_UNUSED int had_err; feature_index = check_feature_index(L, 1); seqid = luaL_checkstring(L, 2); err = gt_error_new(); if (gt_feature_index_has_seqid(*feature_index, &has_seqid, seqid, err)) return gt_lua_error(L, err); gt_error_delete(err); luaL_argcheck(L, has_seqid, 2, "feature_index does not contain seqid"); range = check_range(L, 3); features = gt_array_new(sizeof (GtGenomeNode*)); err = gt_error_new(); had_err = gt_feature_index_get_features_for_range(*feature_index, features, seqid, range, err); if (had_err) return gt_lua_error(L, err); gt_error_delete(err); push_features_as_table(L, features); gt_array_delete(features); return 1; }
static int feature_index_lua_get_range_for_seqid(lua_State *L) { GtFeatureIndex **feature_index; const char *seqid; GtRange range; feature_index = check_feature_index(L, 1); seqid = luaL_checkstring(L, 2); luaL_argcheck(L, gt_feature_index_has_seqid(*feature_index, seqid), 2, "feature_index does not contain seqid"); gt_feature_index_get_range_for_seqid(*feature_index, &range, seqid); return gt_lua_range_push(L, range); }
static int feature_index_lua_has_seqid(lua_State *L) { GtFeatureIndex **feature_index; bool has_seqid; const char *seqid; GtError *err; int had_err = 0; feature_index = check_feature_index(L, 1); seqid = luaL_checkstring(L, 2); err = gt_error_new(); had_err = gt_feature_index_has_seqid(*feature_index, &has_seqid, seqid, err); if (had_err) return gt_lua_error(L, err); gt_error_delete(err); lua_pushboolean(L, has_seqid); return 1; }
static int feature_index_lua_add_feature_node(lua_State *L) { GtFeatureIndex **fi; GtGenomeNode **gn; GtFeatureNode *gf; GtStr *seqid; gt_assert(L); fi = check_feature_index(L, 1); gn = check_genome_node(L, 2); gf = gt_genome_node_cast(gt_feature_node_class(), *gn); luaL_argcheck(L, gf, 2, "not a feature node"); seqid = gt_genome_node_get_seqid(*gn); luaL_argcheck(L, seqid, 2, "feature does not have a sequence id"); luaL_argcheck(L, gt_feature_index_has_seqid(*fi, gt_str_get(seqid)), 2, "feature index does not contain corresponding sequence region"); gt_feature_index_add_feature_node(*fi, gf); return 0; }
static int feature_index_lua_get_features_for_range(lua_State *L) { GtFeatureIndex **feature_index; const char *seqid; GtRange *range; GtArray *features; int had_err; feature_index = check_feature_index(L, 1); seqid = luaL_checkstring(L, 2); luaL_argcheck(L, gt_feature_index_has_seqid(*feature_index, seqid), 2, "feature_index does not contain seqid"); range = check_range(L, 3); features = gt_array_new(sizeof (GtGenomeNode*)); had_err = gt_feature_index_get_features_for_range(*feature_index, features, seqid, range, NULL); gt_assert(!had_err); /* it was checked before that the feature_index contains the given sequence id*/ push_features_as_table(L, features); gt_array_delete(features); return 1; }
static int feature_index_lua_get_range_for_seqid(lua_State *L) { GtFeatureIndex **feature_index; const char *seqid; GtError *err; GtRange range; bool has_seqid; feature_index = check_feature_index(L, 1); seqid = luaL_checkstring(L, 2); err = gt_error_new(); if (gt_feature_index_has_seqid(*feature_index, &has_seqid, seqid, err)) return gt_lua_error(L, err); gt_error_delete(err); luaL_argcheck(L, has_seqid, 2, "feature_index does not contain seqid"); err = gt_error_new(); if (gt_feature_index_get_range_for_seqid(*feature_index, &range, seqid, err)) return gt_lua_error(L, err); gt_error_delete(err); return gt_lua_range_push(L, range); }
static double gaeval_visitor_calculate_coverage(AgnGaevalVisitor *v, GtFeatureNode *genemodel, GtError *error) { agn_assert(v && genemodel); GtStr *seqid = gt_genome_node_get_seqid((GtGenomeNode *)genemodel); GtRange mrna_range = gt_genome_node_get_range((GtGenomeNode *)genemodel); GtArray *overlapping = gt_array_new( sizeof(GtFeatureNode *) ); bool hasseqid; gt_feature_index_has_seqid(v->alignments, &hasseqid, gt_str_get(seqid),error); if(hasseqid) { gt_feature_index_get_features_for_range(v->alignments, overlapping, gt_str_get(seqid), &mrna_range, error); } GtArray *exon_coverage = gt_array_new( sizeof(GtRange) ); GtUword i; for(i = 0; i < gt_array_size(overlapping); i++) { GtFeatureNode *alignment = *(GtFeatureNode **)gt_array_get(overlapping, i); GtArray *covered_parts = gaeval_visitor_intersect((GtGenomeNode*)genemodel, (GtGenomeNode*)alignment); if(covered_parts != NULL) { GtArray *temp = gaeval_visitor_union(exon_coverage, covered_parts); gt_array_delete(covered_parts); gt_array_delete(exon_coverage); exon_coverage = temp; } } double coverage = gaeval_visitor_coverage_resolve(genemodel, exon_coverage); gt_array_delete(exon_coverage); gt_array_delete(overlapping); return coverage; }
static double gaeval_visitor_calculate_integrity(AgnGaevalVisitor *v, GtFeatureNode *genemodel, double coverage, double *components, GtError *error) { agn_assert(v && genemodel); GtStr *seqid = gt_genome_node_get_seqid((GtGenomeNode *)genemodel); GtRange mrna_range = gt_genome_node_get_range((GtGenomeNode *)genemodel); GtArray *overlapping = gt_array_new( sizeof(GtFeatureNode *) ); bool hasseqid; gt_feature_index_has_seqid(v->alignments, &hasseqid, gt_str_get(seqid),error); if(hasseqid) { gt_feature_index_get_features_for_range(v->alignments, overlapping, gt_str_get(seqid), &mrna_range, error); } GtArray *gaps = gt_array_new( sizeof(GtFeatureNode *) ); while(gt_array_size(overlapping) > 0) { GtFeatureNode *alignment = *(GtFeatureNode **)gt_array_pop(overlapping); GtArray *agaps = agn_typecheck_select(alignment, gaeval_visitor_typecheck_gap); gt_array_add_array(gaps, agaps); gt_array_delete(agaps); } gt_array_delete(overlapping); GtUword utr5p_len = agn_mrna_5putr_length(genemodel); double utr5p_score = 0.0; if(utr5p_len >= v->params.exp_5putr_len) utr5p_score = 1.0; else utr5p_score = (double)utr5p_len / (double)v->params.exp_5putr_len; GtUword utr3p_len = agn_mrna_3putr_length(genemodel); double utr3p_score = 0.0; if(utr3p_len >= v->params.exp_3putr_len) utr3p_score = 1.0; else utr3p_score = (double)utr3p_len / (double)v->params.exp_3putr_len; GtArray *introns = agn_typecheck_select(genemodel, agn_typecheck_intron); GtUword exoncount = agn_typecheck_count(genemodel, agn_typecheck_exon); agn_assert(gt_array_size(introns) == exoncount - 1); double structure_score = 0.0; if(gt_array_size(introns) == 0) { GtUword cdslen = agn_mrna_cds_length(genemodel); if(cdslen >= v->params.exp_cds_len) structure_score = 1.0; else structure_score = (double)cdslen / (double)v->params.exp_cds_len; } else { structure_score = gaeval_visitor_introns_confirmed(introns, gaps); } gt_array_delete(gaps); gt_array_delete(introns); double integrity = (v->params.alpha * structure_score) + (v->params.beta * coverage) + (v->params.gamma * utr5p_score) + (v->params.epsilon * utr3p_score); if(components != NULL) { components[0] = structure_score; components[1] = coverage; components[2] = utr5p_score; components[3] = utr3p_score; } return integrity; }
static int gt_sketch_page_runner(GT_UNUSED int argc, const char **argv, int parsed_args, void *tool_arguments, GtError *err) { SketchPageArguments *arguments = tool_arguments; int had_err = 0; GtFeatureIndex *features = NULL; GtRange qry_range, sequence_region_range; GtStyle *sty = NULL; GtStr *prog, *gt_style_file; GtDiagram *d = NULL; GtLayout *l = NULL; GtBioseq *bioseq = NULL; GtCanvas *canvas = NULL; const char *seqid = NULL, *outfile; unsigned long start, height, num_pages = 0; double offsetpos, usable_height; cairo_surface_t *surf = NULL; cairo_t *cr = NULL; GtTextWidthCalculator *twc; gt_error_check(err); features = gt_feature_index_memory_new(); if (cairo_version() < CAIRO_VERSION_ENCODE(1, 8, 6)) gt_warning("Your cairo library (version %s) is older than version 1.8.6! " "These versions contain a bug which may result in " "corrupted PDF output!", cairo_version_string()); /* get style */ sty = gt_style_new(err); if (gt_str_length(arguments->stylefile) == 0) { prog = gt_str_new(); gt_str_append_cstr_nt(prog, argv[0], gt_cstr_length_up_to_char(argv[0], ' ')); gt_style_file = gt_get_gtdata_path(gt_str_get(prog), err); gt_str_delete(prog); gt_str_append_cstr(gt_style_file, "/sketch/default.style"); } else { gt_style_file = gt_str_ref(arguments->stylefile); } had_err = gt_style_load_file(sty, gt_str_get(gt_style_file), err); outfile = argv[parsed_args]; if (!had_err) { /* get features */ had_err = gt_feature_index_add_gff3file(features, argv[parsed_args+1], err); if (!had_err && gt_str_length(arguments->seqid) == 0) { seqid = gt_feature_index_get_first_seqid(features); if (seqid == NULL) { gt_error_set(err, "GFF input file must contain a sequence region!"); had_err = -1; } } else if (!had_err && !gt_feature_index_has_seqid(features, gt_str_get(arguments->seqid))) { gt_error_set(err, "sequence region '%s' does not exist in GFF input file", gt_str_get(arguments->seqid)); had_err = -1; } else if (!had_err) seqid = gt_str_get(arguments->seqid); } /* set text */ if (gt_str_length(arguments->text) == 0) { gt_str_delete(arguments->text); arguments->text = gt_str_new_cstr(argv[parsed_args+1]); } if (!had_err) { /* set display range */ gt_feature_index_get_range_for_seqid(features, &sequence_region_range, seqid); qry_range.start = (arguments->range.start == GT_UNDEF_ULONG ? sequence_region_range.start : arguments->range.start); qry_range.end = (arguments->range.end == GT_UNDEF_ULONG ? sequence_region_range.end : arguments->range.end); /* set output format */ if (strcmp(gt_str_get(arguments->format), "pdf") == 0) { surf = cairo_pdf_surface_create(outfile, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight)); } else if (strcmp(gt_str_get(arguments->format), "ps") == 0) { surf = cairo_ps_surface_create(outfile, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight)); } gt_log_log("created page with %.2f:%.2f dimensions\n", mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight)); offsetpos = TEXT_SPACER + arguments->theight + TEXT_SPACER; usable_height = mm_to_pt(arguments->pheight) - arguments->theight - arguments->theight - 4*TEXT_SPACER; if (gt_str_length(arguments->seqfile) > 0) { bioseq = gt_bioseq_new(gt_str_get(arguments->seqfile), err); } cr = cairo_create(surf); cairo_set_font_size(cr, 8); twc = gt_text_width_calculator_cairo_new(cr, sty); for (start = qry_range.start; start <= qry_range.end; start += arguments->width) { GtRange single_range; GtCustomTrack *ct = NULL; const char *seq; single_range.start = start; single_range.end = start + arguments->width; if (had_err) break; d = gt_diagram_new(features, seqid, &single_range, sty, err); if (!d) { had_err = -1; break; } if (bioseq) { seq = gt_bioseq_get_sequence(bioseq, 0); ct = gt_custom_track_gc_content_new(seq, gt_bioseq_get_sequence_length(bioseq, 0), 800, 70, 0.4, true); gt_diagram_add_custom_track(d, ct); } l = gt_layout_new_with_twc(d, mm_to_pt(arguments->width), sty, twc, err); had_err = gt_layout_get_height(l, &height, err); if (!had_err) { if (gt_double_smaller_double(usable_height - 10 - 2*TEXT_SPACER - arguments->theight, offsetpos + height)) { draw_header(cr, gt_str_get(arguments->text), argv[parsed_args+1], seqid, num_pages, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight), arguments->theight); cairo_show_page(cr); offsetpos = TEXT_SPACER + arguments->theight + TEXT_SPACER; num_pages++; } canvas = gt_canvas_cairo_context_new(sty, cr, offsetpos, mm_to_pt(arguments->pwidth), height, NULL, err); if (!canvas) had_err = -1; offsetpos += height; if (!had_err) had_err = gt_layout_sketch(l, canvas, err); } gt_canvas_delete(canvas); gt_layout_delete(l); gt_diagram_delete(d); if (ct) gt_custom_track_delete(ct); } draw_header(cr, gt_str_get(arguments->text), argv[parsed_args+1], seqid, num_pages, mm_to_pt(arguments->pwidth), mm_to_pt(arguments->pheight), arguments->theight); cairo_show_page(cr); num_pages++; gt_log_log("finished, should be %lu pages\n", num_pages); gt_text_width_calculator_delete(twc); cairo_destroy(cr); cairo_surface_flush(surf); cairo_surface_finish(surf); cairo_surface_destroy(surf); cairo_debug_reset_static_data(); if (bioseq) gt_bioseq_delete(bioseq); gt_style_delete(sty); gt_str_delete(gt_style_file); gt_feature_index_delete(features); } return had_err; }
/* to be called from implementing class! */ int gt_feature_index_unit_test(GtFeatureIndex *fi, GtError *err) { int had_err = 0, i, rval; GtFeatureIndexTestShared sh; GtStrArray *seqids; GtStr *seqid; GtRange check_range; GtRegionNode *rn; bool has_seqid; gt_error_check(err); sh.mutex = gt_mutex_new(); sh.nodes = gt_array_new(sizeof (GtFeatureNode*)); sh.error_count = 0; sh.next_node_idx = 0; sh.fi = fi; sh.err = gt_error_new(); /* create region */ seqid = gt_str_new_cstr(GT_FI_TEST_SEQID); rn = (GtRegionNode*) gt_region_node_new(seqid, GT_FI_TEST_START, GT_FI_TEST_END); /* test seqid is not supposed to exist */ gt_ensure(gt_feature_index_has_seqid(sh.fi, &has_seqid, GT_FI_TEST_SEQID, err) == 0); gt_ensure(!has_seqid); /* add a sequence region directly and check if it has been added */ rval = gt_feature_index_add_region_node(sh.fi, rn, err); gt_ensure(rval == 0); gt_genome_node_delete((GtGenomeNode*) rn); gt_ensure(gt_feature_index_has_seqid(sh.fi, &has_seqid, GT_FI_TEST_SEQID, err) == 0); gt_ensure(has_seqid); gt_feature_index_get_range_for_seqid(sh.fi, &check_range, GT_FI_TEST_SEQID, err); gt_ensure(check_range.start == GT_FI_TEST_START && check_range.end == GT_FI_TEST_END); /* set up nodes to store */ for (i=0;i<GT_FI_TEST_FEATURES_PER_THREAD*gt_jobs;i++) { GtUword start, end; GtFeatureNode *fn; start = random() % (GT_FI_TEST_END - GT_FI_TEST_FEATURE_WIDTH); end = start + random() % (GT_FI_TEST_FEATURE_WIDTH); fn = gt_feature_node_cast(gt_feature_node_new(seqid, "gene", start, end, GT_STRAND_FORWARD)); gt_array_add(sh.nodes, fn); } /* test parallel addition */ gt_multithread(gt_feature_index_unit_test_add, &sh, err); seqids = gt_feature_index_get_seqids(fi, err); gt_ensure(seqids); gt_ensure(gt_feature_index_has_seqid(fi, &has_seqid,GT_FI_TEST_SEQID, err) == 0); gt_ensure(has_seqid); gt_ensure(gt_str_array_size(seqids) == 1); /* test parallel query */ if (!had_err) gt_multithread(gt_feature_index_unit_test_query, &sh, err); gt_ensure(sh.error_count == 0); gt_mutex_delete(sh.mutex); gt_error_delete(sh.err); gt_str_array_delete(seqids); gt_array_delete(sh.nodes); gt_str_delete(seqid); return had_err; }
static int gt_sketch_runner(int argc, const char **argv, int parsed_args, void *tool_arguments, GT_UNUSED GtError *err) { GtSketchArguments *arguments = tool_arguments; GtNodeStream *in_stream = NULL, *add_introns_stream = NULL, *gff3_out_stream = NULL, *feature_stream = NULL, *sort_stream = NULL, *last_stream; GtFeatureIndex *features = NULL; const char *file; char *seqid = NULL; GtRange qry_range, sequence_region_range; GtArray *results = NULL; GtStyle *sty = NULL; GtStr *prog, *defaultstylefile = NULL; GtDiagram *d = NULL; GtLayout *l = NULL; GtImageInfo* ii = NULL; GtCanvas *canvas = NULL; GtUword height; bool has_seqid; int had_err = 0; gt_error_check(err); gt_assert(arguments); prog = gt_str_new(); gt_str_append_cstr_nt(prog, argv[0], gt_cstr_length_up_to_char(argv[0], ' ')); defaultstylefile = gt_get_gtdata_path(gt_str_get(prog), err); gt_str_delete(prog); if (!defaultstylefile) had_err = -1; if (!had_err) { gt_str_append_cstr(defaultstylefile, "/sketch/default.style"); } file = argv[parsed_args]; if (!had_err) { /* create feature index */ features = gt_feature_index_memory_new(); parsed_args++; /* create an input stream */ if (strcmp(gt_str_get(arguments->input), "gff") == 0) { in_stream = gt_gff3_in_stream_new_unsorted(argc - parsed_args, argv + parsed_args); if (arguments->verbose) gt_gff3_in_stream_show_progress_bar((GtGFF3InStream*) in_stream); } else if (strcmp(gt_str_get(arguments->input), "bed") == 0) { if (argc - parsed_args == 0) in_stream = gt_bed_in_stream_new(NULL); else in_stream = gt_bed_in_stream_new(argv[parsed_args]); } else if (strcmp(gt_str_get(arguments->input), "gtf") == 0) { if (argc - parsed_args == 0) in_stream = gt_gtf_in_stream_new(NULL); else in_stream = gt_gtf_in_stream_new(argv[parsed_args]); } last_stream = in_stream; /* create add introns stream if -addintrons was used */ if (arguments->addintrons) { sort_stream = gt_sort_stream_new(last_stream); add_introns_stream = gt_add_introns_stream_new(sort_stream); last_stream = add_introns_stream; } /* create gff3 output stream if -pipe was used */ if (arguments->pipe) { gff3_out_stream = gt_gff3_out_stream_new(last_stream, NULL); last_stream = gff3_out_stream; } /* create feature stream */ feature_stream = gt_feature_stream_new(last_stream, features); /* pull the features through the stream and free them afterwards */ had_err = gt_node_stream_pull(feature_stream, err); gt_node_stream_delete(feature_stream); gt_node_stream_delete(gff3_out_stream); gt_node_stream_delete(sort_stream); gt_node_stream_delete(add_introns_stream); gt_node_stream_delete(in_stream); } if (!had_err) { had_err = gt_feature_index_has_seqid(features, &has_seqid, gt_str_get(arguments->seqid), err); } /* if seqid is empty, take first one added to index */ if (!had_err && strcmp(gt_str_get(arguments->seqid),"") == 0) { seqid = gt_feature_index_get_first_seqid(features, err); if (seqid == NULL) { gt_error_set(err, "GFF input file must contain a sequence region!"); had_err = -1; } } else if (!had_err && !has_seqid) { gt_error_set(err, "sequence region '%s' does not exist in GFF input file", gt_str_get(arguments->seqid)); had_err = -1; } else if (!had_err) seqid = gt_str_get(arguments->seqid); results = gt_array_new(sizeof (GtGenomeNode*)); if (!had_err) { had_err = gt_feature_index_get_range_for_seqid(features, &sequence_region_range, seqid, err); } if (!had_err) { qry_range.start = (arguments->start == GT_UNDEF_UWORD ? sequence_region_range.start : arguments->start); qry_range.end = (arguments->end == GT_UNDEF_UWORD ? sequence_region_range.end : arguments->end); } if (!had_err) { if (arguments->verbose) fprintf(stderr, "# of results: "GT_WU"\n", gt_array_size(results)); /* find and load style file */ if (!(sty = gt_style_new(err))) had_err = -1; if (gt_str_length(arguments->stylefile) == 0) { gt_str_append_str(arguments->stylefile, defaultstylefile); } else { if (!had_err && gt_file_exists(gt_str_get(arguments->stylefile))) { if (arguments->unsafe) gt_style_unsafe_mode(sty); } else { had_err = -1; gt_error_set(err, "style file '%s' does not exist!", gt_str_get(arguments->stylefile)); } } if (!had_err) had_err = gt_style_load_file(sty, gt_str_get(arguments->stylefile), err); } if (!had_err) { /* create and write image file */ if (!(d = gt_diagram_new(features, seqid, &qry_range, sty, err))) had_err = -1; if (!had_err && arguments->flattenfiles) gt_diagram_set_track_selector_func(d, flattened_file_track_selector, NULL); if (had_err || !(l = gt_layout_new(d, arguments->width, sty, err))) had_err = -1; if (!had_err) had_err = gt_layout_get_height(l, &height, err); if (!had_err) { ii = gt_image_info_new(); if (strcmp(gt_str_get(arguments->format),"pdf")==0) { canvas = gt_canvas_cairo_file_new(sty, GT_GRAPHICS_PDF, arguments->width, height, ii, err); } else if (strcmp(gt_str_get(arguments->format),"ps")==0) { canvas = gt_canvas_cairo_file_new(sty, GT_GRAPHICS_PS, arguments->width, height, ii, err); } else if (strcmp(gt_str_get(arguments->format),"svg")==0) { canvas = gt_canvas_cairo_file_new(sty, GT_GRAPHICS_SVG, arguments->width, height, ii, err); } else { canvas = gt_canvas_cairo_file_new(sty, GT_GRAPHICS_PNG, arguments->width, height, ii, err); } if (!canvas) had_err = -1; if (!had_err) { had_err = gt_layout_sketch(l, canvas, err); } if (!had_err) { if (arguments->showrecmaps) { GtUword i; const GtRecMap *rm; for (i = 0; i < gt_image_info_num_of_rec_maps(ii) ;i++) { char buf[BUFSIZ]; rm = gt_image_info_get_rec_map(ii, i); (void) gt_rec_map_format_html_imagemap_coords(rm, buf, BUFSIZ); printf("%s, %s\n", buf, gt_feature_node_get_type(gt_rec_map_get_genome_feature(rm))); } } if (arguments->use_streams) { GtFile *outfile; GtStr *str = gt_str_new(); gt_canvas_cairo_file_to_stream((GtCanvasCairoFile*) canvas, str); outfile = gt_file_open(GT_FILE_MODE_UNCOMPRESSED, file, "w+", err); if (outfile) { gt_file_xwrite(outfile, gt_str_get_mem(str), gt_str_length(str)); gt_file_delete(outfile); } else { had_err = -1; } gt_str_delete(str); } else { had_err = gt_canvas_cairo_file_to_file((GtCanvasCairoFile*) canvas, file, err); } } } } /* free */ gt_free(seqid); gt_canvas_delete(canvas); gt_layout_delete(l); gt_image_info_delete(ii); gt_style_delete(sty); gt_diagram_delete(d); gt_array_delete(results); gt_str_delete(defaultstylefile); gt_feature_index_delete(features); return had_err; }