]> Cypherpunks repositories - keks.git/commitdiff
Tcl code dumper
authorSergey Matveev <stargrave@stargrave.org>
Sun, 13 Apr 2025 12:14:25 +0000 (15:14 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sun, 13 Apr 2025 12:14:25 +0000 (15:14 +0300)
go/cmd/pp/main.go
go/cmd/pp/tcl.go [new file with mode: 0644]

index b26c41cae77e1b142b9afb845b8e284c9ba6dfe9066953c918b476828200cb50..488215e2e5b62d52c76ab74e9c980529e8e2d43bc548ec374defbe7500024906 100644 (file)
@@ -42,7 +42,6 @@ value of the signature's sid.
 }
 
 var (
-       dumpJSON  = flag.Bool("json", false, "Dump as JSON")
        MaxStrLen = flag.Uint("max-str-len", 64,
                "Maximal string length to print")
        MaxParseCycles = flag.Uint64("max-parse-cycles", 1<<63,
@@ -50,6 +49,8 @@ var (
        NoTotals = flag.Bool("no-totals", false, "Do not print how many bytes read")
        onlyV    = flag.Bool("v", false, "Print only values")
        pthStr   = flag.String("p", "", "Print only /that/keks/path")
+       dumpJSON = flag.Bool("json", false, "Dump as JSON")
+       dumpTcl  = flag.Bool("tcl", false, "Dump as Tcl code")
 
        pth []string
 )
@@ -91,12 +92,14 @@ func main() {
                        if err != nil {
                                log.Fatal(err)
                        }
+               } else if *dumpTcl {
+                       tcl(ctx.Iter(), 1, false, false)
                } else {
                        printer(ctx.Iter(), []string{}, 1, false, false)
                }
                off = ctx.Read
        }
-       if !*NoTotals && !*dumpJSON {
+       if !*NoTotals && !*dumpJSON && !*dumpTcl {
                fmt.Println(off, "bytes")
        }
 }
diff --git a/go/cmd/pp/tcl.go b/go/cmd/pp/tcl.go
new file mode 100644 (file)
index 0000000..1c6e622
--- /dev/null
@@ -0,0 +1,146 @@
+// pp -- KEKS pretty printer
+// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, version 3 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+       "encoding/hex"
+       "fmt"
+       "io"
+       "log"
+       "strconv"
+       "time"
+
+       "go.cypherpunks.su/keks"
+       "go.cypherpunks.su/keks/be"
+       "go.cypherpunks.su/keks/types"
+       "go.cypherpunks.su/tai64n/v4"
+)
+
+func tclTAI(t time.Time, ns int, as uint64) {
+       utc, isLeap := tai64n.Leapsecs.Sub(t)
+       if isLeap || utc.Unix() < 0 {
+               fmt.Printf("TAI64 %d %d %d", t.Unix(), ns, as)
+       } else {
+               fmt.Printf("TAI64 [UTCFromISO \"%s\"] %d %d",
+                       utc.Format("2006-01-02 15:04:05"), ns, as)
+       }
+}
+
+func tcl(iter *keks.Iterator, count int, inList, inMap bool) {
+       for range count {
+               if !iter.Next() {
+                       panic("unexpected")
+               }
+               depth := iter.Depth
+               var key string
+               if inMap {
+                       key = iter.Str()
+                       if !iter.Next() {
+                               panic("unexpected")
+                       }
+               }
+               prindent(depth)
+               if inMap {
+                       fmt.Print(key, " ")
+               }
+               if inList || inMap {
+                       fmt.Print("{")
+               }
+               var listOrMap bool
+               switch iter.T {
+               case types.List:
+                       listOrMap = true
+                       fmt.Println("LIST {")
+                       tcl(iter, iter.Len(), true, false)
+                       prindent(depth)
+                       fmt.Print("}")
+               case types.Map:
+                       listOrMap = true
+                       fmt.Println("MAP {")
+                       tcl(iter, iter.Len(), false, true)
+                       prindent(depth)
+                       fmt.Print("}")
+               }
+               if !listOrMap {
+                       switch iter.T {
+                       case types.NIL:
+                               fmt.Print("NIL")
+                       case types.Bool:
+                               if iter.Bool() {
+                                       fmt.Print("TRUE")
+                               } else {
+                                       fmt.Print("FALSE")
+                               }
+                       case types.Hexlet:
+                               h := iter.Hexlet()
+                               fmt.Printf("HEXLET %s", h.UUID())
+                       case types.UInt:
+                               fmt.Printf("INT %d", iter.UInt())
+                       case types.Int:
+                               fmt.Printf("INT %d", iter.Int())
+                       case types.BigInt:
+                               fmt.Printf("INT %d", iter.BigInt())
+                       case types.Blob:
+                               blob := iter.Blob()
+                               v, err := io.ReadAll(blob.Reader())
+                               if err != nil {
+                                       log.Fatal(err)
+                               }
+                               fmt.Printf("BLOB %d [binary decode hex \"%s\"]",
+                                       blob.ChunkLen, hex.EncodeToString(v))
+                       case types.TAI64:
+                               t := iter.TAI64().Time()
+                               tclTAI(t, 0, 0)
+                       case types.TAI64N:
+                               t := iter.TAI64N().Time()
+                               tclTAI(t, t.Nanosecond(), 0)
+                       case types.TAI64NA:
+                               tai := iter.TAI64NA()
+                               var n tai64n.TAI64N
+                               copy(n[:], tai[:])
+                               t := n.Time()
+                               tclTAI(t, t.Nanosecond(), be.Get(tai[12:]))
+                       case types.Magic:
+                               allPrintable := true
+                               magic := iter.Magic()
+                               for _, b := range []byte(magic) {
+                                       if !strconv.IsPrint(rune(b)) {
+                                               allPrintable = false
+                                       }
+                               }
+                               if allPrintable {
+                                       fmt.Printf("MAGIC \"%s\"", magic)
+                               } else {
+                                       fmt.Printf("MAGIC [binary decode hex \"%s\"]", []byte(magic))
+                               }
+                       case types.Bin:
+                               fmt.Printf("BIN [binary decode hex \"%s\"]",
+                                       hex.EncodeToString(iter.Bin()))
+                       case types.Str:
+                               fmt.Printf("STR \"%s\"", iter.Str())
+                       case types.Raw:
+                               fmt.Printf("RAW [binary decode hex \"%s\"]",
+                                       hex.EncodeToString(iter.Raw()))
+                       default:
+                               fmt.Print("???")
+                       }
+               }
+               if inList || inMap {
+                       fmt.Print("}")
+               }
+               fmt.Println("")
+       }
+}