GtNodeVisitor* gt_snp_annotator_visitor_new(GtFeatureNode *gene,
                                            GtTransTable *trans_table,
                                            GtRegionMapping *rmap,
                                            GtError *err)
{
  GtNodeVisitor *nv;
  GtSNPAnnotatorVisitor *sav;
  gt_assert(gene && gt_feature_node_get_type(gene) == gt_symbol(gt_ft_gene));
  nv = gt_node_visitor_create(gt_snp_annotator_visitor_class());
  sav = snp_annotator_visitor_cast(nv);
  sav->gene = (GtFeatureNode*) gt_genome_node_ref((GtGenomeNode*) gene);
  sav->rmap = gt_region_mapping_ref(rmap);
  sav->mRNA_type = gt_symbol(gt_ft_mRNA);
  sav->CDS_type = gt_symbol(gt_ft_CDS);
  sav->SNV_type = gt_symbol(gt_ft_SNV);
  sav->SNP_type = gt_symbol(gt_ft_SNP);
  sav->rnaseqs = gt_hashmap_new(GT_HASH_DIRECT, NULL, gt_free_func);
  if (trans_table) {
    sav->tt = trans_table;
    sav->own_tt = false;
  } else {
    sav->tt = gt_trans_table_new_standard(err);
    sav->own_tt = true;
  }
  if (!sav->tt || gt_snp_annotator_visitor_prepare_gene(sav, err) != 0) {
    gt_node_visitor_delete(nv);
    return NULL;
  }
  return nv;
}
Esempio n. 2
0
GtBlock* gt_block_clone(GtBlock *block)
{
  GtBlock* newblock;
  GtUword i;
  gt_assert(block);
  newblock = gt_block_new();
  for (i=0;i<gt_array_size(block->elements);i++)
  {
    GtElement *elem;
    elem = gt_element_ref(*(GtElement**) gt_array_get(block->elements, i));
    gt_assert(elem);
    gt_array_add(newblock->elements, elem);
  }
  gt_assert(gt_block_get_size(newblock) == gt_block_get_size(block));
  newblock->caption = gt_str_ref(block->caption);
  newblock->type = block->type;
  newblock->range.start = block->range.start;
  newblock->range.end = block->range.end;
  newblock->show_caption = block->show_caption;
  newblock->strand = block->strand;
  newblock->top_level_feature = (GtFeatureNode*)
                                gt_genome_node_ref((GtGenomeNode*)
                                                   block->top_level_feature);
  return newblock;
}
Esempio n. 3
0
void gt_feature_info_add(GtFeatureInfo *fi, const char *id, GtFeatureNode *fn)
{
  gt_assert(fi && id && fn);
  gt_assert(!gt_feature_node_is_pseudo((GtFeatureNode*) fn));
  gt_hashmap_add(fi->id_to_genome_node, gt_cstr_dup(id),
                 gt_genome_node_ref((GtGenomeNode*) fn));
}
Esempio n. 4
0
static int lua_custom_visitor_visit_node_generic(GT_UNUSED GtNodeVisitor *nv,
                                                 GtGenomeNode *fn,
                                                 const char *function,
                                                 GtError *err)
{
  GT_UNUSED GtNodeVisitor **vis;
  GtLuaCustomVisitor *lcv;
  GT_UNUSED GtGenomeNode **node;
  int had_err = 0;
  gt_assert(nv);
  lcv = lua_custom_visitor_cast(nv);

  node = check_genome_node(lcv->L, 1);
  vis = check_genome_visitor(lcv->L, 2);
  gt_assert(*node == (GtGenomeNode*) fn);
  gt_assert(*vis == (GtNodeVisitor*) nv);
  lua_pushvalue(lcv->L, 2);
  lua_pushstring(lcv->L, function);
  lua_gettable(lcv->L, 2);
  if (lua_isnil(lcv->L, -1)) {
    lua_pop(lcv->L, 1);
    return had_err;
  }
  lua_pushvalue(lcv->L, 2);
  gt_lua_genome_node_push(lcv->L, gt_genome_node_ref((GtGenomeNode*) fn));
  if (lua_pcall(lcv->L, 2, 0, 0)) {
    const char *error = lua_tostring(lcv->L, -1);
    gt_error_set(err, "%s", error);
    had_err = -1;
  }
  return had_err;
}
Esempio n. 5
0
void gt_feature_info_add_pseudo_parent(GtFeatureInfo *fi, const char *id,
                                       GtFeatureNode *pseudo_parent)
{
  gt_assert(fi && id && pseudo_parent);
  gt_assert(gt_feature_node_is_pseudo((GtFeatureNode*) pseudo_parent));
  gt_hashmap_add(fi->id_to_pseudo_parent, gt_cstr_dup(id),
                 gt_genome_node_ref((GtGenomeNode*) pseudo_parent));
}
Esempio n. 6
0
static GtFeatureNodeIterator* feature_node_iterator_new_base(const GtFeatureNode
                                                             *fn)
{
  GtFeatureNodeIterator *fni;
  gt_assert(fn);
  fni = gt_malloc(sizeof *fni);
  fni->fn = (GtFeatureNode*) gt_genome_node_ref((GtGenomeNode*) fn);
  fni->feature_stack = gt_array_new(sizeof (GtFeatureNode*));
  return fni;
}
Esempio n. 7
0
static int filter_stream_next(GtNodeStream *ns, GtGenomeNode **gn,
                              GtError *error)
{
  AgnFilterStream *stream;
  GtFeatureNode *fn;
  int had_err;
  gt_error_check(error);
  stream = filter_stream_cast(ns);

  if(gt_queue_size(stream->cache) > 0)
  {
    *gn = gt_queue_get(stream->cache);
    return 0;
  }

  while(1)
  {
    had_err = gt_node_stream_next(stream->in_stream, gn, error);
    if(had_err)
      return had_err;
    if(!*gn)
      return 0;

    fn = gt_feature_node_try_cast(*gn);
    if(!fn)
      return 0;

    GtFeatureNode *current;
    GtFeatureNodeIterator *iter = gt_feature_node_iterator_new(fn);
    for(current  = gt_feature_node_iterator_next(iter);
        current != NULL;
        current  = gt_feature_node_iterator_next(iter))
    {
      const char *type = gt_feature_node_get_type(current);
      bool keepfeature = false;
      if(gt_hashmap_get(stream->typestokeep, type) != NULL)
        keepfeature = true;

      if(keepfeature)
      {
        gt_genome_node_ref((GtGenomeNode *)current);
        gt_queue_add(stream->cache, current);
      }
    }
    gt_feature_node_iterator_delete(iter);
    gt_genome_node_delete((GtGenomeNode *)fn);
    if(gt_queue_size(stream->cache) > 0)
    {
      *gn = gt_queue_get(stream->cache);
      return 0;
    }
  }

  return 0;
}
static int gt_ltr_cluster_stream_next(GtNodeStream *ns,
                                      GtGenomeNode **gn,
                                      GtError *err)
{
  GtLTRClusterStream *lcs;
  GtGenomeNode *ref_gn;
  int had_err = 0;
  unsigned long i = 0;

  gt_error_check(err);
  lcs = gt_ltr_cluster_stream_cast(ns);
  if (lcs->first_next) {
    while (!(had_err = gt_node_stream_next(lcs->in_stream, gn, err)) && *gn) {
      gt_assert(*gn && !had_err);
      ref_gn = gt_genome_node_ref(*gn);
      gt_array_add(lcs->nodes, ref_gn);
      had_err = gt_genome_node_accept(*gn, (GtNodeVisitor*) lcs->lcv, err);
      if (had_err) {
        gt_genome_node_delete(*gn);
        *gn = NULL;
        break;
      }
    }
    lcs->feat_to_encseq =
                       gt_ltr_cluster_prepare_seq_visitor_get_encseqs(lcs->lcv);
    lcs->feat_to_encseq_keys =
                      gt_ltr_cluster_prepare_seq_visitor_get_features(lcs->lcv);
    if (!had_err) {
      for (i = 0; i < gt_str_array_size(lcs->feat_to_encseq_keys); i++) {
        had_err = process_feature(lcs,
                                  gt_str_array_get(lcs->feat_to_encseq_keys, i),
                                  err);
        if (had_err)
          break;
      }
    }
    if (!had_err) {
      *gn = *(GtGenomeNode**) gt_array_get(lcs->nodes, lcs->next_index);
      lcs->next_index++;
      lcs->first_next = false;
      return 0;
    }
  } else {
    if (lcs->next_index >= gt_array_size(lcs->nodes))
      *gn = NULL;
    else {
      *gn = *(GtGenomeNode**) gt_array_get(lcs->nodes, lcs->next_index);
      lcs->next_index++;
    }
    return 0;
  }

  return had_err;
}
static int feature_node_iterator_lua_next(lua_State *L)
{
  GtFeatureNodeIterator **fni;
  GtFeatureNode *fn;
  fni = check_gt_feature_node_iterator(L, 1);
  fn = gt_feature_node_iterator_next(*fni);
  if (fn)
    gt_lua_genome_node_push(L, gt_genome_node_ref((GtGenomeNode*) fn));
  else
    lua_pushnil(L);
  return 1;
}
Esempio n. 10
0
GtRecMap* gt_rec_map_new(double nw_x, double nw_y, double se_x, double se_y,
                         GtFeatureNode *node)
{
  GtRecMap *rm = gt_calloc(1, sizeof (GtRecMap));
  rm->nw_x = nw_x;
  rm->nw_y = nw_y;
  rm->se_x = se_x;
  rm->se_y = se_y;
  rm->fn = (GtFeatureNode*) gt_genome_node_ref((GtGenomeNode*) node);
  rm->has_omitted_children = false;
  return rm;
}
Esempio n. 11
0
GtBlock* gt_block_new_from_node(GtFeatureNode *node)
{
  GtBlock *block;
  gt_assert(node);
  block = gt_block_new();
  block->range = gt_genome_node_get_range((GtGenomeNode*) node);
  block->strand = gt_feature_node_get_strand(node);
  block->type = gt_feature_node_get_type(node);
  if (!gt_feature_node_is_pseudo(node)) {
    block->top_level_feature = (GtFeatureNode*)
                               gt_genome_node_ref((GtGenomeNode*) node);
  }
  return block;
}
Esempio n. 12
0
static int genome_node_lua_add_child(lua_State *L)
{
  GtGenomeNode **parent, **child;
  GtFeatureNode *pf, *cf;
  parent = check_genome_node(L, 1);
  child  = check_genome_node(L, 2);
  pf = gt_feature_node_try_cast(*parent);
  luaL_argcheck(L, pf, 1, "not a feature node");
  cf = gt_feature_node_try_cast(*child);
  luaL_argcheck(L, cf, 2, "not a feature node");
  gt_feature_node_add_child(pf, (GtFeatureNode*)
                                gt_genome_node_ref((GtGenomeNode*) cf));
  return 0;
}
Esempio n. 13
0
void gt_block_insert_element(GtBlock *block, GtFeatureNode *node)
{
  GtElement *element;
  gt_assert(block && node);
  if (!block->top_level_feature) {
    block->top_level_feature = (GtFeatureNode*)
                               gt_genome_node_ref((GtGenomeNode*) node);
  }
  element = gt_element_new(node);
  /* invalidate sortedness flag because insertion of element at the end
     may break ordering */
  block->sorted = false;
  gt_array_add(block->elements, element);
}
Esempio n. 14
0
int gt_script_filter_run(GtScriptFilter *sf, GtFeatureNode *gf,
                         bool *select_node, GtError *err)
{
  int had_err = 0;
#ifndef NDEBUG
  int stack_size;
#endif
  GtGenomeNode *gn_lua;

#ifndef NDEBUG
  stack_size = lua_gettop(sf->L);
#endif

  if (!had_err) {
    lua_getglobal(sf->L, "filter");
    if (lua_isnil(sf->L, -1)) {
      gt_error_set(err, "function 'filter' is not defined");
      had_err = -1;
      lua_pop(sf->L, 1);
    }
  }

  if (!had_err) {
    gn_lua = gt_genome_node_ref((GtGenomeNode*) gf);
    gt_lua_genome_node_push(sf->L, gn_lua);

    if (lua_pcall(sf->L, 1, 1, 0) != 0) {
      gt_error_set(err, "error running function 'filter': %s",
                   lua_tostring(sf->L, -1));
      lua_pop(sf->L, 1);
      had_err = -1;
    }
  }

  if (!had_err && !lua_isboolean(sf->L, -1)) {
    gt_error_set(err, "function 'filter' must return boolean");
    lua_pop(sf->L, 1);
    had_err = -1;
  }

  if (!had_err) {
    *select_node = lua_toboolean(sf->L, -1);
    lua_pop(sf->L, 1);
  }
  gt_assert(lua_gettop(sf->L) == stack_size);

  return had_err;
}
Esempio n. 15
0
static void push_features_as_table(lua_State *L, GtArray *features)
{
  unsigned long i;
  if (features && gt_array_size(features)) {
    /* push table containing feature references onto the stack */
    lua_newtable(L);
    for (i = 0; i < gt_array_size(features); i++) {
      lua_pushinteger(L, i+1); /* in Lua we index from 1 on */
      gt_lua_genome_node_push(L, gt_genome_node_ref(*(GtGenomeNode**)
                                                  gt_array_get(features, i)));
      lua_rawset(L, -3);
    }
  }
  else
    lua_pushnil(L);
}
Esempio n. 16
0
static int buffer_stream_next(GtNodeStream *ns, GtGenomeNode **gn, GtError *err)
{
  GtBufferStream *bs;
  gt_error_check(err);
  bs = buffer_stream_cast(ns);
  if (bs->buffering) {
    int had_err = gt_node_stream_next(bs->in_stream, gn, err);
    if (!had_err && *gn)
      gt_queue_add(bs->node_buffer, gt_genome_node_ref(*gn));
    return had_err;
  }
  else {
    *gn = gt_queue_size(bs->node_buffer) ? gt_queue_get(bs->node_buffer) : NULL;
    return 0;
  }
}
Esempio n. 17
0
static int lua_custom_stream_next(GtNodeStream *ns, GtGenomeNode **gn,
                                  GtError *err)
{
  GT_UNUSED GtNodeStream **s;
  GtGenomeNode **retnode;
  GtLuaCustomStream *lcs;
  int had_err = 0;
  gt_assert(ns);
  gt_error_check(err);
  lcs = lua_custom_stream_cast(ns);

  /* push correct Lua object for this stream */
  lua_rawgeti(lcs->L, LUA_REGISTRYINDEX, lcs->ref);
  s = check_genome_stream(lcs->L, -1);

  /* get overridden next_tree method */
  lua_pushstring(lcs->L, "next_tree");
  lua_gettable(lcs->L, -2);

  /* make sure there is one */
  gt_assert(!lua_isnil(lcs->L, -1));
  lua_pushvalue(lcs->L, -2);

  if (lua_pcall(lcs->L, 1, 1, 0)) {
    const char *error = lua_tostring(lcs->L, -1);
    gt_error_set(err, "%s", error);
    had_err = -1;
  }

  if (!had_err) {
    if (lua_isnil(lcs->L, -1)) {
      *gn = NULL;
    } else {
      retnode = gt_lua_try_checkudata(lcs->L, -1, GENOME_NODE_METATABLE);
      if (!retnode) {
        const char *type;
        type = lua_tostring(lcs->L, -1);
        gt_error_set(err, "custom 'next_tree' method must return a genome "
                          "node or nil, was %s", type);
        had_err = -1;
      } else {
        *gn = gt_genome_node_ref(*retnode);
      }
    }
  }
  return had_err;
}
Esempio n. 18
0
static int feature_in_stream_next(GtNodeStream *ns, GtGenomeNode **gn,
                                   GtError *error)
{
  GtFeatureInStream *stream = feature_in_stream_cast(ns);
  gt_error_check(error);

  if (!stream->init)
  {
    feature_in_stream_init(stream);
    stream->init = true;
  }

  if (gt_queue_size(stream->regioncache) > 0)
  {
    GtGenomeNode *region = gt_queue_get(stream->regioncache);
    *gn = region;
    return 0;
  }

  if (stream->featurecache == NULL || gt_array_size(stream->featurecache) == 0)
  {
    if (stream->featurecache != NULL)
    {
      gt_array_delete(stream->featurecache);
      stream->featurecache = NULL;
    }

    if (stream->seqindex == gt_str_array_size(stream->seqids))
    {
      *gn = NULL;
      return 0;
    }

    const char *seqid = gt_str_array_get(stream->seqids, stream->seqindex++);
    stream->featurecache = gt_feature_index_get_features_for_seqid(stream->fi,
                                                                   seqid,
                                                                   error);
    gt_array_sort(stream->featurecache, (GtCompare)gt_genome_node_compare);
    gt_array_reverse(stream->featurecache);
  }

  GtGenomeNode *feat = *(GtGenomeNode **)gt_array_pop(stream->featurecache);
  *gn = gt_genome_node_ref(feat);
  return 0;
}
Esempio n. 19
0
static int gt_array_out_stream_next(GtNodeStream *gs, GtGenomeNode **gn,
                                    GtError *err)
{
  GtArrayOutStream *aos;
  GtGenomeNode *node, *gn_ref;
  int had_err = 0;

  gt_error_check(err);
  aos = gt_array_out_stream_cast(gs);
  had_err = gt_node_stream_next(aos->in_stream, gn, err);

  if (!had_err && *gn) {
    if ((node = gt_feature_node_try_cast(*gn))) {
      gn_ref = gt_genome_node_ref(*gn);
      gt_array_add(aos->nodes, gn_ref);
    }
  }

  return had_err;
}
Esempio n. 20
0
static void push_recmap_as_table(lua_State *L, const GtRecMap *rm)
{
    gt_assert(rm);
    lua_newtable(L);
    lua_pushstring(L, "nw_x");
    lua_pushnumber(L, gt_rec_map_get_northwest_x(rm));
    lua_rawset(L, -3);
    lua_pushstring(L, "nw_y");
    lua_pushnumber(L, gt_rec_map_get_northwest_y(rm));
    lua_rawset(L, -3);
    lua_pushstring(L, "se_x");
    lua_pushnumber(L, gt_rec_map_get_southeast_x(rm));
    lua_rawset(L, -3);
    lua_pushstring(L, "se_y");
    lua_pushnumber(L, gt_rec_map_get_southeast_y(rm));
    lua_rawset(L, -3);
    lua_pushstring(L, "feature_ref");
    gt_lua_genome_node_push(L, gt_genome_node_ref((GtGenomeNode*)
                            gt_rec_map_get_genome_feature(rm)));
    lua_rawset(L, -3);
}
Esempio n. 21
0
static int feature_node_lua_get_exons(lua_State *L)
{
  GtGenomeNode **gn = check_genome_node(L, 1);
  GtArray *exons = gt_array_new(sizeof (GtGenomeNode*));
  GtUword i = 0;
  GtFeatureNode *fn;
  /* make sure we get a feature node */
  fn = gt_feature_node_try_cast(*gn);
  luaL_argcheck(L, fn, 1, "not a feature node");
  gt_feature_node_get_exons(fn, exons);
  lua_newtable(L);
  for (i = 0; i < gt_array_size(exons); i++) {
    lua_pushnumber(L, i+1);
    gt_lua_genome_node_push(L, (GtGenomeNode*)
                            gt_genome_node_ref(*(GtGenomeNode**)
                                               gt_array_get(exons, i)));
    lua_rawset(L, -3);
  }
  gt_array_delete(exons);
  return 1;
}
static int snp_annotator_stream_next(GtNodeStream *ns, GtGenomeNode **gn,
                                     GtError *err)
{
  GtSNPAnnotatorStream *sas;
  int had_err = 0;
  bool complete_cluster = false;
  GtGenomeNode *mygn = NULL;
  GtFeatureNode *fn = NULL;
  const char *snv_type = gt_symbol(gt_ft_SNV),
             *snp_type = gt_symbol(gt_ft_SNP),
             *gene_type = gt_symbol(gt_ft_gene);
  gt_error_check(err);
  sas = gt_snp_annotator_stream_cast(ns);

  /* if there are still SNPs left in the buffer, output them */
  if (gt_queue_size(sas->outqueue) > 0) {
    *gn = (GtGenomeNode*) gt_queue_get(sas->outqueue);
    return had_err;
  } else complete_cluster = false;

  while (!had_err && !complete_cluster) {
    had_err = gt_node_stream_next(sas->merge_stream, &mygn, err);

    /* stop if stream is at the end */
    if (had_err || !mygn) break;

    /* process all feature nodes */
    if ((fn = gt_feature_node_try_cast(mygn))) {
      GtGenomeNode *addgn;
      const char *type = gt_feature_node_get_type(fn);
      GtRange new_rng = gt_genome_node_get_range(mygn);
      if (type == snv_type || type == snp_type) {
        /* -----> this is a SNP <----- */
        if (gt_range_overlap(&new_rng, &sas->cur_gene_range)) {
          /* it falls into the currently observed range */
          gt_queue_add(sas->snps, gt_genome_node_ref((GtGenomeNode*) fn));
        } else {
          /* SNP outside a gene, this cluster is done
             add to out queue and start serving */
          gt_assert(gt_queue_size(sas->outqueue) == 0);
          had_err = snp_annotator_stream_process_current_gene(sas, err);
          gt_queue_add(sas->outqueue, mygn);
          if (gt_queue_size(sas->outqueue) > 0) {
            *gn = (GtGenomeNode*) gt_queue_get(sas->outqueue);
            complete_cluster = true;
          }
        }
      } else if (type == gene_type) {
        /* -----> this is a gene <----- */
        if (gt_array_size(sas->cur_gene_set) == 0UL) {
          /* new overlapping gene cluster */
          addgn = gt_genome_node_ref(mygn);
          gt_array_add(sas->cur_gene_set, addgn);
          sas->cur_gene_range = gt_genome_node_get_range(mygn);
        } else {
          if (gt_range_overlap(&new_rng, &sas->cur_gene_range)) {
            /* gene overlaps with current one, add to cluster */
            addgn = gt_genome_node_ref(mygn);
            gt_array_add(sas->cur_gene_set, addgn);
            sas->cur_gene_range = gt_range_join(&sas->cur_gene_range, &new_rng);
          } else {
            /* finish current cluster and start a new one */
            had_err = snp_annotator_stream_process_current_gene(sas, err);
            if (!had_err) {
              addgn = gt_genome_node_ref(mygn);
              gt_array_add(sas->cur_gene_set, addgn);
              sas->cur_gene_range = gt_genome_node_get_range(mygn);
            }
            if (gt_queue_size(sas->outqueue) > 0) {
              *gn = (GtGenomeNode*) gt_queue_get(sas->outqueue);
              complete_cluster = true;
            }
          }
        }
        /* from now on, genes are kept in gene cluster arrays only */
        gt_genome_node_delete(mygn);
      }
    } else {
      /* meta node */
      had_err = snp_annotator_stream_process_current_gene(sas, err);
      if (!had_err) {
        gt_queue_add(sas->outqueue, mygn);
      }
      if (gt_queue_size(sas->outqueue) > 0) {
        *gn = (GtGenomeNode*) gt_queue_get(sas->outqueue);
        complete_cluster = true;
      }
    }
  }

  return had_err;
}
Esempio n. 23
0
static int construct_mRNAs(GT_UNUSED void *key, void *value, void *data,
                           GtError *err)
{
  ConstructionInfo *cinfo = (ConstructionInfo*) data;
  GtArray *gt_genome_node_array = (GtArray*) value,
          *mRNAs = (GtArray*) cinfo->mRNAs;
  GtGenomeNode *mRNA_node, *first_node, *gn;
  const char *tname;
  GtStrand mRNA_strand;
  GtRange mRNA_range;
  GtStr *mRNA_seqid;
  GtUword i;
  int had_err = 0;

  gt_error_check(err);
  gt_assert(key && value && data);
   /* at least one node in array */
  gt_assert(gt_array_size(gt_genome_node_array));

  /* determine the range and the strand of the mRNA */
  first_node = *(GtGenomeNode**) gt_array_get(gt_genome_node_array, 0);
  mRNA_range = gt_genome_node_get_range(first_node);
  mRNA_strand = gt_feature_node_get_strand((GtFeatureNode*) first_node);
  mRNA_seqid = gt_genome_node_get_seqid(first_node);

  /* TODO: support discontinuous start/stop codons */
  for (i = 0; !had_err && i < gt_array_size(gt_genome_node_array); i++) {
    gn = *(GtGenomeNode**) gt_array_get(gt_genome_node_array, i);
    if (gt_feature_node_get_attribute((GtFeatureNode*) gn,
        GTF_PARSER_STOP_CODON_FLAG)) {
      GtUword j;
      GtRange stop_codon_rng = gt_genome_node_get_range(gn);
      bool found_cds = false;
      for (j = 0; !had_err && j < gt_array_size(gt_genome_node_array); j++) {
        GtGenomeNode* gn2;
        GtRange this_rng;
        const char *this_type;
        gn2 = *(GtGenomeNode**) gt_array_get(gt_genome_node_array, j);
        if (gn == gn2) continue;
        this_rng = gt_genome_node_get_range(gn2);
        this_type = gt_feature_node_get_type((GtFeatureNode*) gn2);
        if (this_type == gt_symbol(gt_ft_CDS)) {
          if (gt_range_contains(&this_rng, &stop_codon_rng)) {
            if (cinfo->tidy) {
              gt_warning("stop codon on line %u in file %s is contained in "
                         "CDS in line %u",
                         gt_genome_node_get_line_number(gn),
                         gt_genome_node_get_filename(gn),
                         gt_genome_node_get_line_number(gn2));
              found_cds = true;
            } else {
              gt_error_set(err, "stop codon on line %u in file %s is "
                                "contained in CDS in line %u",
                           gt_genome_node_get_line_number(gn),
                           gt_genome_node_get_filename(gn),
                           gt_genome_node_get_line_number(gn2));
              had_err = -1;
            }
            break;
          }
          if (this_rng.end + 1 == stop_codon_rng.start) {
            this_rng.end = stop_codon_rng.end;
            gt_genome_node_set_range(gn2, &this_rng);
            found_cds = true;
            break;
          }
          if (this_rng.start == stop_codon_rng.end + 1) {
            this_rng.start = stop_codon_rng.start;
            gt_genome_node_set_range(gn2, &this_rng);
            found_cds = true;
            break;
          }
        }
      }
      if (!found_cds) {
        if (!had_err) {
          if (cinfo->tidy) {
            gt_warning("found stop codon on line %u in file %s with no "
                       "flanking CDS, ignoring it",
                       gt_genome_node_get_line_number(gn),
                       gt_genome_node_get_filename(gn));
          } else {
            gt_error_set(err, "found stop codon on line %u in file %s with no "
                              "flanking CDS",
                         gt_genome_node_get_line_number(gn),
                         gt_genome_node_get_filename(gn));
            had_err = -1;
            break;
          }
        }
      } else {
        gt_array_rem(gt_genome_node_array, i);
        gt_genome_node_delete(gn);
      }
    }
  }

  for (i = 1; !had_err && i < gt_array_size(gt_genome_node_array); i++) {
    GtRange range;
    GtStrand strand;
    gn = *(GtGenomeNode**) gt_array_get(gt_genome_node_array, i);
    range = gt_genome_node_get_range(gn);
    mRNA_range = gt_range_join(&mRNA_range, &range);
    strand = gt_feature_node_get_strand((GtFeatureNode*) gn);
    if (strand != mRNA_strand) {
      gt_error_set(err, "feature %s on line %u has strand %c, but the "
                        "parent transcript has strand %c",
                   (const char*) key,
                   gt_genome_node_get_line_number(gn),
                   GT_STRAND_CHARS[strand],
                   GT_STRAND_CHARS[mRNA_strand]);
      had_err = -1;
      break;
    } else {
      mRNA_strand = gt_strand_join(mRNA_strand, strand);
    }
    if (!had_err && gt_str_cmp(mRNA_seqid, gt_genome_node_get_seqid(gn))) {
      gt_error_set(err, "The features on lines %u and %u refer to different "
                "genomic sequences (``seqname''), although they have the same "
                "gene IDs (``gene_id'') which must be globally unique",
                gt_genome_node_get_line_number(first_node),
                gt_genome_node_get_line_number(gn));
      had_err = -1;
      break;
    }
  }

  if (!had_err) {
    mRNA_node = gt_feature_node_new(mRNA_seqid, gt_ft_mRNA, mRNA_range.start,
                                    mRNA_range.end, mRNA_strand);
    gt_feature_node_add_attribute(((GtFeatureNode*) mRNA_node), "ID", key);
    gt_feature_node_add_attribute(((GtFeatureNode*) mRNA_node), "transcript_id",
                                  key);

    if ((tname = gt_hashmap_get(cinfo->transcript_id_to_name_mapping,
                              (const char*) key)) && strlen(tname) > 0) {
      gt_feature_node_add_attribute((GtFeatureNode*) mRNA_node, GT_GFF_NAME,
                                      tname);
    }

    /* register children */
    for (i = 0; i < gt_array_size(gt_genome_node_array); i++) {
      gn = *(GtGenomeNode**) gt_array_get(gt_genome_node_array, i);
      gt_feature_node_add_child((GtFeatureNode*) mRNA_node,
                                (GtFeatureNode*) gt_genome_node_ref(gn));
    }

    /* store the mRNA */
    gt_array_add(mRNAs, mRNA_node);
  }

  return had_err;
}