func (self *Reader) commentMetaline(line string) (f *feat.Feature, err error) { // Load these into a slice in a MetaField of the Feature fields := strings.Split(string(line), " ") switch fields[0] { case "gff-version": self.Version, err = strconv.Atoi(fields[1]) if err != nil { self.Version = DefaultVersion } return self.Read() case "source-version": if len(fields) > 1 { self.SourceVersion = strings.Join(fields[1:], " ") return self.Read() } else { return nil, bio.NewError("Incomplete source-version metaline", 0, fields) } case "date": if len(fields) > 1 { self.Date, err = time.Parse(self.TimeFormat, strings.Join(fields[1:], " ")) return self.Read() } else { return nil, bio.NewError("Incomplete date metaline", 0, fields) } case "Type": if len(fields) > 1 { self.Type = bio.ParseMoltype(fields[1]) return self.Read() } else { return nil, bio.NewError("Incomplete Type metaline", 0, fields) } case "sequence-region": if len(fields) > 3 { var start, end int start, err = strconv.Atoi(fields[2]) if err != nil { return nil, err } else { if self.OneBased { start = bio.OneToZero(start) } } end, err = strconv.Atoi(fields[3]) if err != nil { return nil, err } f = &feat.Feature{ Meta: &feat.Feature{ ID: fields[1], Start: start, End: end, }, } } else { return nil, bio.NewError("Incomplete sequence-region metaline", 0, fields) } case "DNA", "RNA", "Protein": if len(fields) > 1 { var s *seq.Seq s, err = self.metaSequence(fields[0], fields[1]) if err != nil { return } else { f = &feat.Feature{Meta: s} } } else { return nil, bio.NewError("Incomplete sequence metaline", 0, fields) } default: f = &feat.Feature{Meta: line} } return }
// Read a single feature or part and return it or an error. func (self *Reader) Read() (f *feat.Feature, err error) { var ( line string elems []string s int8 ok bool ) for { line, err = self.r.ReadString('\n') if err != nil { return } if len(line) > 0 && line[len(line)-1] == '\r' { line = line[:len(line)-1] } line = strings.TrimSpace(line) if len(line) == 0 { // ignore blank lines continue } else if strings.HasPrefix(line, "##") { f, err = self.commentMetaline(line[2:]) return } else if line[0] != '#' { // ignore comments elems = strings.SplitN(line, "\t", 10) break } } if s, ok = charToStrand[elems[strandField]]; !ok { s = 0 } startPos, se := strconv.Atoi(elems[startField]) if se != nil { startPos = 0 } else { if self.OneBased { startPos = bio.OneToZero(startPos) } } endPos, se := strconv.Atoi(elems[endField]) if se != nil { endPos = 0 } fr, se := strconv.Atoi(elems[frameField]) if se != nil { fr = -1 } score, se := strconv.ParseFloat(elems[scoreField], 64) var scorePtr *float64 if se != nil { scorePtr = nil } else { scorePtr = &score } f = &feat.Feature{ ID: elems[nameField] + ":" + strconv.Itoa(startPos) + ".." + strconv.Itoa(endPos), Location: elems[nameField], Source: elems[sourceField], Start: startPos, End: endPos, Feature: elems[featureField], Score: scorePtr, Frame: int8(fr), Strand: s, Moltype: self.Type, // currently we default to bio.DNA } if len(elems) > attributeField { f.Attributes = elems[attributeField] } if len(elems) > commentField { f.Comments = elems[commentField] } return }