diff --git a/sentence.go b/sentence.go index 325fb27..bec76fc 100644 --- a/sentence.go +++ b/sentence.go @@ -110,15 +110,16 @@ func (p *SentenceParser) parseBaseSentence(raw string) (BaseSentence, error) { if raw == "" { return BaseSentence{}, errors.New("nmea: can not parse empty input") } - tagBlock, raw, ok, err := ParseTagBlock(raw) + tagBlock, sentenceStartIndex, err := ParseTagBlock(raw) if err != nil { return BaseSentence{}, err } - if ok && p.OnTagBlock != nil { + if sentenceStartIndex > 0 && p.OnTagBlock != nil { if err := p.OnTagBlock(tagBlock); err != nil { return BaseSentence{}, err } } + raw = raw[sentenceStartIndex:] startIndex := strings.IndexAny(raw, SentenceStart+SentenceStartEncapsulated) if startIndex != 0 { diff --git a/tagblock.go b/tagblock.go index 1bf59fb..29a432d 100644 --- a/tagblock.go +++ b/tagblock.go @@ -18,13 +18,12 @@ type TagBlock struct { } // ParseTagBlock parses tag blocks from a sentence string. -// The second return value contains the sentence with tag block removed. -// The third return value indicates if a tag block was found. +// The second return value is the index where the sentence starts. // See: https://gpsd.gitlab.io/gpsd/AIVDM.html#_nmea_tag_blocks -func ParseTagBlock(raw string) (TagBlock, string, bool, error) { +func ParseTagBlock(raw string) (TagBlock, int, error) { startOfTagBlock := strings.IndexByte(raw, TagBlockSep) if startOfTagBlock == -1 { - return TagBlock{}, raw, false, nil + return TagBlock{}, 0, nil } // tag block is always at the start of line (unless IEC 61162-450). Starts with `\` and ends with `\` and has valid sentence // following or @@ -32,12 +31,12 @@ func ParseTagBlock(raw string) (TagBlock, string, bool, error) { // Note: tag block group can span multiple lines but we only parse ones that have sentence endOfTagBlock := strings.LastIndexByte(raw, TagBlockSep) if endOfTagBlock <= startOfTagBlock { - return TagBlock{}, "", false, fmt.Errorf("nmea: sentence tag block is missing '\\' at the end") + return TagBlock{}, 0, fmt.Errorf("nmea: sentence tag block is missing '\\' at the end") } tags := raw[startOfTagBlock+1 : endOfTagBlock] sumSepIndex := strings.Index(tags, ChecksumSep) if sumSepIndex == -1 { - return TagBlock{}, "", false, fmt.Errorf("nmea: tagblock does not contain checksum separator") + return TagBlock{}, 0, fmt.Errorf("nmea: tagblock does not contain checksum separator") } var ( @@ -50,21 +49,21 @@ func ParseTagBlock(raw string) (TagBlock, string, bool, error) { // Validate the checksum if checksum != checksumRaw { - return TagBlock{}, "", false, fmt.Errorf("nmea: tagblock checksum mismatch [%s != %s]", checksum, checksumRaw) + return TagBlock{}, 0, fmt.Errorf("nmea: tagblock checksum mismatch [%s != %s]", checksum, checksumRaw) } items := strings.Split(tags[:sumSepIndex], ",") for _, item := range items { parts := strings.SplitN(item, ":", 2) if len(parts) != 2 { - return TagBlock{}, "", false, fmt.Errorf("nmea: tagblock field is malformed (should be :) [%s]", item) + return TagBlock{}, 0, fmt.Errorf("nmea: tagblock field is malformed (should be :) [%s]", item) } key, value := parts[0], parts[1] switch key { case "c": // UNIX timestamp tagBlock.Time, err = parseInt64(value) if err != nil { - return TagBlock{}, "", false, err + return TagBlock{}, 0, err } case "d": // Destination ID tagBlock.Destination = value @@ -73,12 +72,12 @@ func ParseTagBlock(raw string) (TagBlock, string, bool, error) { case "n": // Line count tagBlock.LineCount, err = parseInt64(value) if err != nil { - return TagBlock{}, "", false, err + return TagBlock{}, 0, err } case "r": // Relative time tagBlock.RelativeTime, err = parseInt64(value) if err != nil { - return TagBlock{}, "", false, err + return TagBlock{}, 0, err } case "s": // Source ID tagBlock.Source = value @@ -86,7 +85,7 @@ func ParseTagBlock(raw string) (TagBlock, string, bool, error) { tagBlock.Text = value } } - return tagBlock, raw[endOfTagBlock+1:], true, nil + return tagBlock, endOfTagBlock + 1, nil } func parseInt64(raw string) (int64, error) { diff --git a/tagblock_test.go b/tagblock_test.go index 9cf37dd..e343184 100644 --- a/tagblock_test.go +++ b/tagblock_test.go @@ -7,12 +7,11 @@ import ( ) var tagblocktests = []struct { - name string - raw string - err string - block TagBlock - ok bool - remaining string + name string + raw string + err string + block TagBlock + index int }{ { @@ -22,8 +21,7 @@ var tagblocktests = []struct { Time: 1553390539, Source: "Satelite_1", }, - ok: true, - remaining: "!AIVDM,1,2,3", + index: 30, }, { @@ -33,8 +31,7 @@ var tagblocktests = []struct { Time: 1564827317, Source: "satelite", }, - ok: true, - remaining: "!AIVDM,1,2,3", + index: 28, }, { @@ -44,8 +41,7 @@ var tagblocktests = []struct { Time: 1564827317, Source: "", }, - ok: true, - remaining: "!AIVDM,1,2,3", + index: 28, }, { name: "Test unix timestamp", @@ -54,8 +50,7 @@ var tagblocktests = []struct { Time: 1564827317, Source: "", }, - ok: true, - remaining: "!AIVDM,1,2,3", + index: 28, }, { @@ -65,8 +60,7 @@ var tagblocktests = []struct { Time: 1564827317000, Source: "", }, - ok: true, - remaining: "!AIVDM,1,2,3", + index: 31, }, { @@ -81,8 +75,7 @@ var tagblocktests = []struct { Text: "helloworld", LineCount: 13, }, - ok: true, - remaining: "!AIVDM,1,2,3", + index: 72, }, { @@ -121,24 +114,22 @@ var tagblocktests = []struct { err: "nmea: tagblock unable to parse uint64 [gjadslkg]", }, { - name: "Test no tagblock", - raw: "!AIVDM,1,2,3", - remaining: "!AIVDM,1,2,3", + name: "Test no tagblock", + raw: "!AIVDM,1,2,3", }, } func TestParseTagBlock(t *testing.T) { for _, tt := range tagblocktests { t.Run(tt.name, func(t *testing.T) { - b, remaining, ok, err := ParseTagBlock(tt.raw) + b, index, err := ParseTagBlock(tt.raw) if tt.err != "" { assert.Error(t, err) } else { assert.NoError(t, err) } assert.Equal(t, tt.block, b) - assert.Equal(t, tt.remaining, remaining) - assert.Equal(t, tt.ok, ok) + assert.Equal(t, tt.index, index) }) } }