From 0984fb9b401112c9cb1b9e8c31cad36259b47e2adef90b01b47dc5736d53f9e9 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Wed, 8 Jan 2025 19:02:22 +0300 Subject: [PATCH] Add optional offsets storage --- go/atom-decode.go | 3 +++ go/cmd/print/main.go | 54 ++++++++++++++++++++++++++++++-------------- go/ctx.go | 10 +++++--- go/iter.go | 6 +++++ go/parse.go | 3 +++ 5 files changed, 56 insertions(+), 20 deletions(-) diff --git a/go/atom-decode.go b/go/atom-decode.go index bc4096e..443ed14 100644 --- a/go/atom-decode.go +++ b/go/atom-decode.go @@ -37,6 +37,9 @@ var ( ) func (ctx *Decoder) DecodeAtom() (t types.Type, err error) { + if ctx.opts != nil && ctx.opts.SaveOffsets { + ctx.offsets = append(ctx.offsets, ctx.Read) + } var tag byte tag, err = ctx.getByte() if err != nil { diff --git a/go/cmd/print/main.go b/go/cmd/print/main.go index 7b308c3..9890008 100644 --- a/go/cmd/print/main.go +++ b/go/cmd/print/main.go @@ -41,6 +41,16 @@ func hexenc(b []byte) string { return strings.ToUpper(hex.EncodeToString(b)) } +func printbin(s []byte) { + sLen := len(s) + var dots string + if sLen > int(*MaxStrLen) { + s = s[:int(*MaxStrLen)] + dots = "..." + } + fmt.Printf("%s%d%s:%s%s\n", Magenta, sLen, Reset, hexenc(s), dots) +} + func printer(iter *keks.Iterator, count int, inList, inMap bool) { for i := 0; i < count; i++ { if !iter.Next() { @@ -48,26 +58,31 @@ func printer(iter *keks.Iterator, count int, inList, inMap bool) { } depth := iter.Depth fmt.Print(Blue + strconv.Itoa(depth) + Reset) + var key string + if inMap { + key = iter.Str() + if !iter.Next() { + panic("unexpected") + } + } + fmt.Printf(" %s%03d%s ", Red, iter.Offset(), Reset) prindent(depth) if inList { fmt.Printf("%s%d:%s ", Yellow, i, Reset) } else if inMap { - fmt.Printf("%s%s%s: ", Green, iter.Str(), Reset) - if !iter.Next() { - panic("unexpected") - } + fmt.Printf("%s%s%s: ", Green, key, Reset) } switch iter.T { case types.List: fmt.Printf("[ %s%d%s\n", Cyan, iter.Len(), Reset) printer(iter, iter.Len(), true, false) prindent(depth) - fmt.Println(" ]") + fmt.Println(" " + " ]") case types.Map: fmt.Printf("{ %s%d%s\n", Cyan, iter.Len(), Reset) printer(iter, iter.Len(), false, true) prindent(depth) - fmt.Println(" }") + fmt.Println(" " + " }") case types.NIL: fmt.Println("NIL") @@ -88,10 +103,17 @@ func printer(iter *keks.Iterator, count int, inList, inMap bool) { case types.Blob: blob := iter.Blob() fmt.Printf("BLOB[ %s%d l=%d%s\n", Cyan, len(blob.Chunks), blob.ChunkLen, Reset) + off := iter.Offset() + 1 + 8 for i, chunk := range blob.Chunks { - fmt.Print(strings.Repeat(" ", iter.Depth+1)) - fmt.Printf("%d: %d:%s\n", i, len(chunk), hexenc([]byte(chunk))) + fmt.Print(Blue + strconv.Itoa(depth+1) + Reset) + fmt.Printf(" %s%03d%s ", Red, off, Reset) + prindent(depth + 1) + fmt.Printf("%s%d:%s ", Yellow, i, Reset) + printbin([]byte(chunk)) + off += int64(len(chunk)) + 1 } + prindent(depth) + fmt.Println(" " + " ]") case types.TAI64: t := iter.TAI64().Time() utc, isLeap := tai64n.Leapsecs.Sub(t) @@ -116,17 +138,12 @@ func printer(iter *keks.Iterator, count int, inList, inMap bool) { t := iter.TAI64NA() fmt.Printf("TAI64NA(%s)\n", hexenc(t[:])) case types.Bin: - s := iter.Bin() - var dots string - if len(s) > int(*MaxStrLen) { - s = s[:int(*MaxStrLen)] - dots = "..." - } - fmt.Printf("%s%d%s:%s%s\n", Magenta, len(s), Reset, hexenc(s), dots) + printbin(iter.Bin()) case types.Str: fmt.Print(`"`) s := iter.Str() - if len(s) > int(*MaxStrLen) { + sLen := len(s) + if sLen > int(*MaxStrLen) { fmt.Print(s[:int(*MaxStrLen)]) fmt.Print("...") } else { @@ -143,7 +160,10 @@ func printer(iter *keks.Iterator, count int, inList, inMap bool) { func main() { flag.Parse() - ctx := keks.NewDecoderFromReader(bufio.NewReader(os.Stdin), nil) + ctx := keks.NewDecoderFromReader( + bufio.NewReader(os.Stdin), + &keks.DecodeOpts{SaveOffsets: true}, + ) _, err := ctx.Parse() if err != nil { log.Fatal(err) diff --git a/go/ctx.go b/go/ctx.go index 3e7f903..7546f66 100644 --- a/go/ctx.go +++ b/go/ctx.go @@ -38,6 +38,9 @@ type DecodeOpts struct { // Leave TAI64* values as is, do not convert to time.Time during unmarshal. LeaveTAI64 bool + + // Store items offsets. + SaveOffsets bool } type Decoder struct { @@ -50,9 +53,10 @@ type Decoder struct { opts *DecodeOpts - depth int8 - types []types.Type - depths []int8 + depth int8 + types []types.Type + depths []int8 + offsets []int64 bigints []*big.Int bools []bool diff --git a/go/iter.go b/go/iter.go index bb327f7..4776138 100644 --- a/go/iter.go +++ b/go/iter.go @@ -93,6 +93,12 @@ func (iter *Iterator) Next() bool { return true } +// Get item's absolute offset. +// Available only if was decoded with opts.SaveOffsets=true. +func (iter *Iterator) Offset() int64 { + return iter.ctx.offsets[iter.i] +} + func (iter *Iterator) Bool() bool { return iter.ctx.bools[iter.bools] } diff --git a/go/parse.go b/go/parse.go index 8b4107b..769fb5a 100644 --- a/go/parse.go +++ b/go/parse.go @@ -33,6 +33,9 @@ var ( func (ctx *Decoder) deTail() { ctx.types = ctx.types[:len(ctx.types)-1] ctx.depths = ctx.depths[:len(ctx.depths)-1] + if ctx.opts != nil && ctx.opts.SaveOffsets { + ctx.offsets = ctx.offsets[:len(ctx.offsets)-1] + } } func (ctx *Decoder) parse() (t types.Type, err error) { -- 2.50.0