]> Cypherpunks repositories - keks.git/commitdiff
Unify Go and C printers output
authorSergey Matveev <stargrave@stargrave.org>
Fri, 27 Dec 2024 12:31:50 +0000 (15:31 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sat, 28 Dec 2024 11:19:57 +0000 (14:19 +0300)
15 files changed:
c/cmd/lib/printai.c
c/cmd/print-items/print-items.c
c/cmd/print-itered/print-itered.c
c/cmd/test-vector/test-vector.c
c/doc/atom.texi
c/lib/dec.c
c/lib/dec.h
c/lib/enc.c
c/lib/enc.h
c/lib/items.c
go/cmd/iter-print/main.go [deleted file]
go/cmd/print/colour.go [new file with mode: 0644]
go/cmd/print/main.go
go/go.mod
go/go.sum

index 7d6ef8a8ecd80b6cf05bec992831255674dc8757927c640d383ef42ddf6100b8..a5914886d27622305c6e25fd72de1b203ada1e2ccb7308a4eb3f66777dc96333 100644 (file)
@@ -9,6 +9,19 @@
 #include "hex.h"
 #include "printai.h"
 
+static void
+printDT(const struct tm *tm, const struct timespec *tv, const size_t len)
+{
+    {
+        char human[20] = {0};
+        strftime(human, sizeof human, "%Y-%m-%d %H:%M:%S", tm);
+        fputs(human, stdout);
+    }
+    if (len == 12) {
+        fprintf(stdout, ".%09zu", tv->tv_nsec);
+    }
+}
+
 enum KEKSErr
 PrintTAI64(const unsigned char *buf, const size_t len)
 {
@@ -45,6 +58,16 @@ PrintTAI64(const unsigned char *buf, const size_t len)
     default:
         return err;
     }
+    time_t t = tv.tv_sec;
+    struct tm *tm = localtime(&t);
+    if (tm == NULL) {
+        hex = HexEnc(buf, len);
+        fprintf(stdout, "TAI unrepresentable: %s)\n", hex);
+        free(hex);
+        return KEKSErrNo;
+    }
+    printDT(tm, &tv, len);
+    fputs(" TAI, ", stdout);
     err = KEKSTimespecToUTC(&tv);
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wswitch-enum"
@@ -53,29 +76,21 @@ PrintTAI64(const unsigned char *buf, const size_t len)
     case KEKSErrNo:
         break;
     case KEKSErrTAI64InPast:
-        hex = HexEnc(buf, len);
-        fprintf(stdout, "in past: %s)\n", hex);
-        free(hex);
+        fputs("UTC in past)", stdout);
+        return KEKSErrNo;
+    case KEKSErrTAI64IsLeap:
+        fputs("leap)", stdout);
         return KEKSErrNo;
     default:
         return err;
     }
-    time_t t = tv.tv_sec;
-    struct tm *tm = localtime(&t);
+    t = tv.tv_sec;
+    tm = localtime(&t);
     if (tm == NULL) {
-        hex = HexEnc(buf, len);
-        fprintf(stdout, "unrepresentable: %s)\n", hex);
-        free(hex);
+        fputs("UTC unrepresentable)", stdout);
         return KEKSErrNo;
     }
-    {
-        char human[20] = {0};
-        strftime(human, sizeof human, "%Y-%m-%d %H:%M:%S", tm);
-        fputs(human, stdout);
-    }
-    if (len == 12) {
-        fprintf(stdout, ".%09zu", tv.tv_nsec);
-    }
-    fputs(")\n", stdout);
+    printDT(tm, &tv, len);
+    fputs(" UTC)\n", stdout);
     return KEKSErrNo;
 }
index 4df28424c65bfd3635b774e7e8d167f83b5f60ecff050b0e4f391586964704ca..379ae2317685fedb0e88ce3b2845cf57506bfbf12cb9bc59fd4705adb93751db 100644 (file)
 #include "../lib/printai.h"
 #include "../lib/uuid.h"
 
-static const char *ColourRed = "\x1b[31m";
-static const char *ColourGreen = "\x1b[32m";
-static const char *ColourYellow = "\x1b[33m";
-static const char *ColourBlue = "\x1b[34m";
-static const char *ColourMagenta = "\x1b[35m";
-static const char *ColourCyan = "\x1b[36m";
-static const char *ColourWhite = "\x1b[37m";
-static const char *ColourReset = "\x1b[0m";
+static char *ColourRed = "\x1b[31m";
+static char *ColourGreen = "\x1b[32m";
+static char *ColourYellow = "\x1b[33m";
+static char *ColourBlue = "\x1b[34m";
+static char *ColourMagenta = "\x1b[35m";
+static char *ColourCyan = "\x1b[36m";
+static char *ColourWhite = "\x1b[37m";
+static char *ColourReset = "\x1b[0m";
 
 static size_t MaxStrLen = 40;
-static bool NoColour = false;
 static bool NoOffsets = false;
 static int OffDigits = 0;
 static char OffFmt[16] = {0};
@@ -82,36 +81,16 @@ printer( // NOLINT(misc-no-recursion)
     if (NoOffsets) {
         fputs("  ", stdout);
     } else {
-        fprintf(
-            stdout,
-            "%s%zd%s ",
-            NoColour ? "" : ColourBlue,
-            indent,
-            NoColour ? "" : ColourReset);
-        fprintf(
-            stdout,
-            OffFmt,
-            NoColour ? "" : ColourRed,
-            items->offsets[idx],
-            NoColour ? "" : ColourReset);
+        fprintf(stdout, "%s%zd%s ", ColourBlue, indent, ColourReset);
+        fprintf(stdout, OffFmt, ColourRed, items->offsets[idx], ColourReset);
     }
     struct KEKSItem *item = &(items->list[idx]);
     printIndent(indent);
     if (inList) {
-        fprintf(
-            stdout,
-            "%s%zu:%s ",
-            NoColour ? "" : ColourYellow,
-            listIdx,
-            NoColour ? "" : ColourReset);
+        fprintf(stdout, "%s%zu:%s ", ColourYellow, listIdx, ColourReset);
     }
     if (mapKey != NULL) {
-        fprintf(
-            stdout,
-            "%s%s:%s ",
-            NoColour ? "" : ColourGreen,
-            mapKey,
-            NoColour ? "" : ColourReset);
+        fprintf(stdout, "%s%s:%s ", ColourGreen, mapKey, ColourReset);
     }
     char *str = NULL;
     enum KEKSErr err = KEKSErrInvalid;
@@ -139,12 +118,7 @@ printer( // NOLINT(misc-no-recursion)
         fprintf(stdout, "%zd\n", item->atom.v.nint);
         break;
     case KEKSItemList: {
-        fprintf(
-            stdout,
-            "[ %s%zd%s\n",
-            NoColour ? "" : ColourCyan,
-            item->atom.v.list.len,
-            NoColour ? "" : ColourReset);
+        fprintf(stdout, "[ %s%zd%s\n", ColourCyan, item->atom.v.list.len, ColourReset);
         indent++;
         idx = item->atom.v.list.head;
         listIdx = 0;
@@ -165,12 +139,7 @@ printer( // NOLINT(misc-no-recursion)
         break;
     }
     case KEKSItemMap: {
-        fprintf(
-            stdout,
-            "{ %s%zd%s\n",
-            NoColour ? "" : ColourCyan,
-            item->atom.v.list.len,
-            NoColour ? "" : ColourReset);
+        fprintf(stdout, "{ %s%zd%s\n", ColourCyan, item->atom.v.list.len, ColourReset);
         indent++;
         idx = item->atom.v.list.head;
         while (idx != 0) {
@@ -197,10 +166,10 @@ printer( // NOLINT(misc-no-recursion)
         fprintf(
             stdout,
             "BLOB[ %s%zu l=%zu%s\n",
-            NoColour ? "" : ColourCyan,
+            ColourCyan,
             item->atom.v.blob.chunks,
             item->atom.v.blob.chunkLen,
-            NoColour ? "" : ColourReset);
+            ColourReset);
         indent++;
         idx++;
         listIdx = 0;
@@ -236,9 +205,9 @@ printer( // NOLINT(misc-no-recursion)
         fprintf(
             stdout,
             "%s%zu:%s%s%s\n",
-            NoColour ? "" : ColourMagenta,
+            ColourMagenta,
             item->atom.v.str.len,
-            NoColour ? "" : ColourReset,
+            ColourReset,
             str,
             (item->atom.v.str.len > MaxStrLen) ? "..." : "");
         free(str);
@@ -255,8 +224,7 @@ printer( // NOLINT(misc-no-recursion)
     }
     case KEKSItemRaw:
         str = HexEnc(item->atom.v.str.ptr, item->atom.v.str.len);
-        fprintf(
-            stdout, "(t=0x%X l=%zu v=%s)\n", item->atom.tag, item->atom.v.str.len, str);
+        fprintf(stdout, "(l=%zu v=%s)\n", item->atom.v.str.len, str);
         free(str);
         break;
     case KEKSItemEOC:
@@ -274,7 +242,6 @@ main(int argc, char **argv)
     bool noTotals = false;
     bool onlyTotals = false;
     ptrdiff_t itemsInitialLen = 2048;
-    NoColour = getenv("NO_COLOR") != NULL;
     struct option longopts[] = {
         {"max-str-len", required_argument, NULL, 'a'},
         {"do-encode", no_argument, NULL, 'b'},
@@ -341,6 +308,17 @@ main(int argc, char **argv)
         usage();
     }
 
+    if (getenv("NO_COLOR") != NULL) {
+        ColourRed = "";
+        ColourGreen = "";
+        ColourYellow = "";
+        ColourBlue = "";
+        ColourMagenta = "";
+        ColourCyan = "";
+        ColourWhite = "";
+        ColourReset = "";
+    }
+
     size_t len = 0;
     unsigned char *buf = NULL;
     if (!Mmap(&buf, &len, argv[0])) {
@@ -378,6 +356,7 @@ main(int argc, char **argv)
         return EXIT_FAILURE;
     }
     if (!onlyTotals) {
+        setenv("TZ", "UTC", 1);
         err = printer(&items, 0, 0, false, 0, NULL);
         if (err != KEKSErrNo) {
             fprintf(stderr, "err: %s\n", KEKSErr2Str(err));
index 1cc13ac060edbc028a87b557608a36c9348949fb8a68f11c062b754a5a6d5c9b..80520efdd04ee76d529be6ba47a2fcecc0342224c58d806554eca9e91b729cb4 100644 (file)
@@ -146,7 +146,7 @@ myCb(
     }
     case KEKSItemRaw:
         hex = HexEnc(atom->v.str.ptr, atom->v.str.len);
-        fprintf(stdout, "(t=0x%X l=%zu v=%s)\n", atom->tag, atom->v.str.len, hex);
+        fprintf(stdout, "(l=%zu v=%s)\n", atom->v.str.len, hex);
         free(hex);
         break;
     default:
index 3eebe6e8b32b1ae6e6dd6263809df6b57be46a0cb063f9f43282b87421bb945d..790378c20cbade05e7c2a8f1ad885c91a81eaa32ea70d4c6c437771964d7ed5b 100644 (file)
@@ -59,14 +59,14 @@ main(void)
     adder(KEKSAtomBinEncode(&Got, buf + Off, len - Off, bin, 63 + 255 + 65535 + 1));
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .str.bin
 
-    adder(
-        KEKSAtomStrEncode(&Got, buf + Off, len - Off, (const unsigned char *)"utf8", 4));
+    adder(KEKSAtomStrEncode(
+        &Got, buf + Off, len - Off, (const unsigned char *)"utf8", 4));
     adder(KEKSAtomStrEncode(
         &Got, buf + Off, len - Off, (const unsigned char *)"привет мир", 19));
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .str
 
-    adder(
-        KEKSAtomStrEncode(&Got, buf + Off, len - Off, (const unsigned char *)"blob", 4));
+    adder(KEKSAtomStrEncode(
+        &Got, buf + Off, len - Off, (const unsigned char *)"blob", 4));
     adder(KEKSAtomListEncode(&Got, buf + Off, len - Off)); // .blob
 
     adder(KEKSAtomBlobEncode(&Got, buf + Off, len - Off, 12)); // .blob.0
@@ -92,15 +92,15 @@ main(void)
 
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .blob
 
-    adder(
-        KEKSAtomStrEncode(&Got, buf + Off, len - Off, (const unsigned char *)"bool", 4));
+    adder(KEKSAtomStrEncode(
+        &Got, buf + Off, len - Off, (const unsigned char *)"bool", 4));
     adder(KEKSAtomListEncode(&Got, buf + Off, len - Off)); // .bool
     adder(KEKSAtomBoolEncode(&Got, buf + Off, len - Off, true));
     adder(KEKSAtomBoolEncode(&Got, buf + Off, len - Off, false));
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .bool
 
-    adder(
-        KEKSAtomStrEncode(&Got, buf + Off, len - Off, (const unsigned char *)"ints", 4));
+    adder(KEKSAtomStrEncode(
+        &Got, buf + Off, len - Off, (const unsigned char *)"ints", 4));
     adder(KEKSAtomMapEncode(&Got, buf + Off, len - Off)); // .ints
 
     adder(
@@ -113,29 +113,38 @@ main(void)
     adder(KEKSAtomSintEncode(&Got, buf + Off, len - Off, -123));
     adder(KEKSAtomSintEncode(&Got, buf + Off, len - Off, -1234));
     adder(KEKSAtomSintEncode(&Got, buf + Off, len - Off, -12345678));
-    adder(KEKSAtomRawEncode(
-        &Got,
-        buf + Off,
-        len - Off,
-        KEKSAtomNint,
-        (const unsigned char *)"\x8A\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
-        11));
-    adder(KEKSAtomRawEncode(
-        &Got,
-        buf + Off,
-        len - Off,
-        KEKSAtomNint,
-        (const unsigned char
-             *)"\x91\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
-        18));
-    adder(KEKSAtomRawEncode(
-        &Got,
-        buf + Off,
-        len - Off,
-        KEKSAtomNint,
-        (const unsigned char
-             *)"\xBE\x00\xA1\xE5\xA4\x61\x28\x03\x41\x85\x6D\x4A\xD9\x08\xA6\x9E\xA5\xF3\xCC\xC1\x0C\x78\x82\x14\x2B\xB7\xD8\x01\xCC\x38\x0F\x26\xB6\xB4\xD6\x96\x32\x02\x4E\xE5\x21\xF8\xCF\xAF\xB4\x43\xD4\x9A\x2A\x3D\x0C\xC7\x3B\xB4\x75\x7E\x88\x2F\x53\x96\xED\x30\x2B\x41\x82\x10\xD0\xD4\x9D\x71\xBE\x86\xCA\x69\x9C\xF5\xEE\x3B\xD6\xD5\x7E\xD6\x58\xE6\x93\x16\x22\x96\x44\xBA\x65\x0C\x92\xD7\xF0\xD4\xDB\x29\xC3\xAD\x1D\xFA\x99\x79\x16\x6F\x4C\x6E\x79\x56\x1A\x58\xF8\xE2\xC6\x3D\x08\xDF\x4E\x22\x46\xED\x1F\x64\xD2\xD6\x13\xA1\x9D\x8C\x9A\x68\x70\xE6\x18\x8E\x2F\x3A\xD4\x0C\x03\x8F\xDA\x30\x45\x2F\x8D\xDF\xCD\x21\x2A\x6A\x97\x4B\xC2\x5E\xC6\xA0\x56\x4C\x66\xA7\xD2\x87\x50\xFF\x9D\xB4\x58\xB7\x44\x41\xE4\x9E\xE5\xE8\x2D\xBF\x49\x74\xD6\x45\x67\x8E\x0A\xD0\x31\xF9\x7A\xAB\xA8\x55\x45\x1E\xEF\x17\xA8\x9B\x42\x82\x1E\x53\x08\x16\xDD\x57\x93\xA8\x3B\x7A\x82\xE8\xED\xE8\x1E\x7F\x33\x95\x69\x1F\x76\x17\x84\xF8\xBC\x62\x79\x61\xCD\x40\x84\x5E\xE9\x08\xA4\x0B\x9D\x1F\x01\x92\x7B\x38\xEB\x1A\x7D\x4E\xFD\x60\xDB\x09\x44\xF7\xEC\x1B\x83\x2B\x7E\x6E\xB1\x83\x3F\x9A\x35\x15\x76\xAD\x5D\xE5\x71\xFA\xE8\x86\x5D\xA7\x51\x4F\x06\xB0\xFB\xF3\x8C\x1F\x2A\x85\x38\xF5\xD3\x8B\x4E\x18\x00\x1C\xCB\xB9\xDD\xCB\x48\x85\x30\xF6\x08\x6D\x14\x74\x4D\x8B\x56\x72\x16\x6E\x48\xE9\xEF\x93\x77\x25\x75\xDB\x66\xB6\xF2\x57\xC6\xFF\xAD\x6E\x2C\x29\x15\x10\xC5\xED\x02\xE1\xA8\xB2\x4B\x44\xEC\x1E\x2A\x91\x68\x62\x38\xE8\xDE\xFD\x18\xC0\x19\x98\x63\x4A\x50\x76\xA6\xB7\xF8\x5F\xC8\x1A\x1D\x61\xA1\x5B\x2C\x52\x8D\xFA\x08\x2C\xE3\xE3\xE2\xCA\x64\x9A\xC0\x48\x17\xEC\x5C\x12\x3E\x0B\x76\x1A\xB1\x03\xF7\x80\xC0\x14\xF0\x21\xBB\xEB\x7E\xA3\xB8\x6E\x0C\xA1\xC8\x33\xE3\x8E\xF5\xC8\x97\xA6\xD7\xE1\xF4\xA2\x39\x8C\x49\x0B\x3D\x65\xE2\xF4\x5C\x7F\xAE\x40\x2D\x1D\xF1\x69\x8B\x6F\xDD\xB1\x85\x48\x16\x64\x87\x1C\x26\x64\xBF\xD1\x68\x6B\x2B\x33\x72\x78\x3F\x18\x56\xF6\x24\x7A\x3F\x84\x37\xA2\x81\x8F\x68\xB7\xC4\xEA\x13\xA5\xF5\x7B\x73\xC7\x28\x70\xB6\x84\x04\x5F\x14",
-        481));
+    {
+        buf[Off] = KEKSAtomNint;
+        Off++;
+        size_t l = 11;
+        memcpy(
+            buf + Off,
+            (const unsigned char *)"\x8A\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
+            l);
+        Off += l;
+    }
+    {
+        buf[Off] = KEKSAtomNint;
+        Off++;
+        size_t l = 18;
+        memcpy(
+            buf + Off,
+            (const unsigned char
+                 *)"\x91\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+            l);
+        Off += l;
+    }
+    {
+        buf[Off] = KEKSAtomNint;
+        Off++;
+        size_t l = 481;
+        memcpy(
+            buf + Off,
+            (const unsigned char
+                 *)"\xBE\x00\xA1\xE5\xA4\x61\x28\x03\x41\x85\x6D\x4A\xD9\x08\xA6\x9E\xA5\xF3\xCC\xC1\x0C\x78\x82\x14\x2B\xB7\xD8\x01\xCC\x38\x0F\x26\xB6\xB4\xD6\x96\x32\x02\x4E\xE5\x21\xF8\xCF\xAF\xB4\x43\xD4\x9A\x2A\x3D\x0C\xC7\x3B\xB4\x75\x7E\x88\x2F\x53\x96\xED\x30\x2B\x41\x82\x10\xD0\xD4\x9D\x71\xBE\x86\xCA\x69\x9C\xF5\xEE\x3B\xD6\xD5\x7E\xD6\x58\xE6\x93\x16\x22\x96\x44\xBA\x65\x0C\x92\xD7\xF0\xD4\xDB\x29\xC3\xAD\x1D\xFA\x99\x79\x16\x6F\x4C\x6E\x79\x56\x1A\x58\xF8\xE2\xC6\x3D\x08\xDF\x4E\x22\x46\xED\x1F\x64\xD2\xD6\x13\xA1\x9D\x8C\x9A\x68\x70\xE6\x18\x8E\x2F\x3A\xD4\x0C\x03\x8F\xDA\x30\x45\x2F\x8D\xDF\xCD\x21\x2A\x6A\x97\x4B\xC2\x5E\xC6\xA0\x56\x4C\x66\xA7\xD2\x87\x50\xFF\x9D\xB4\x58\xB7\x44\x41\xE4\x9E\xE5\xE8\x2D\xBF\x49\x74\xD6\x45\x67\x8E\x0A\xD0\x31\xF9\x7A\xAB\xA8\x55\x45\x1E\xEF\x17\xA8\x9B\x42\x82\x1E\x53\x08\x16\xDD\x57\x93\xA8\x3B\x7A\x82\xE8\xED\xE8\x1E\x7F\x33\x95\x69\x1F\x76\x17\x84\xF8\xBC\x62\x79\x61\xCD\x40\x84\x5E\xE9\x08\xA4\x0B\x9D\x1F\x01\x92\x7B\x38\xEB\x1A\x7D\x4E\xFD\x60\xDB\x09\x44\xF7\xEC\x1B\x83\x2B\x7E\x6E\xB1\x83\x3F\x9A\x35\x15\x76\xAD\x5D\xE5\x71\xFA\xE8\x86\x5D\xA7\x51\x4F\x06\xB0\xFB\xF3\x8C\x1F\x2A\x85\x38\xF5\xD3\x8B\x4E\x18\x00\x1C\xCB\xB9\xDD\xCB\x48\x85\x30\xF6\x08\x6D\x14\x74\x4D\x8B\x56\x72\x16\x6E\x48\xE9\xEF\x93\x77\x25\x75\xDB\x66\xB6\xF2\x57\xC6\xFF\xAD\x6E\x2C\x29\x15\x10\xC5\xED\x02\xE1\xA8\xB2\x4B\x44\xEC\x1E\x2A\x91\x68\x62\x38\xE8\xDE\xFD\x18\xC0\x19\x98\x63\x4A\x50\x76\xA6\xB7\xF8\x5F\xC8\x1A\x1D\x61\xA1\x5B\x2C\x52\x8D\xFA\x08\x2C\xE3\xE3\xE2\xCA\x64\x9A\xC0\x48\x17\xEC\x5C\x12\x3E\x0B\x76\x1A\xB1\x03\xF7\x80\xC0\x14\xF0\x21\xBB\xEB\x7E\xA3\xB8\x6E\x0C\xA1\xC8\x33\xE3\x8E\xF5\xC8\x97\xA6\xD7\xE1\xF4\xA2\x39\x8C\x49\x0B\x3D\x65\xE2\xF4\x5C\x7F\xAE\x40\x2D\x1D\xF1\x69\x8B\x6F\xDD\xB1\x85\x48\x16\x64\x87\x1C\x26\x64\xBF\xD1\x68\x6B\x2B\x33\x72\x78\x3F\x18\x56\xF6\x24\x7A\x3F\x84\x37\xA2\x81\x8F\x68\xB7\xC4\xEA\x13\xA5\xF5\x7B\x73\xC7\x28\x70\xB6\x84\x04\x5F\x14",
+            l);
+        Off += l;
+    }
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .ints.neg
 
     adder(
@@ -148,27 +157,33 @@ main(void)
     adder(KEKSAtomUintEncode(&Got, buf + Off, len - Off, 123));
     adder(KEKSAtomUintEncode(&Got, buf + Off, len - Off, 1234));
     adder(KEKSAtomUintEncode(&Got, buf + Off, len - Off, 12345678));
-    adder(KEKSAtomRawEncode(
-        &Got,
-        buf + Off,
-        len - Off,
-        KEKSAtomPint,
-        (const unsigned char *)"\x8B\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
-        12));
-    adder(KEKSAtomRawEncode(
-        &Got,
-        buf + Off,
-        len - Off,
-        KEKSAtomPint,
-        (const unsigned char
-             *)"\x91\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
-        18));
+    {
+        buf[Off] = KEKSAtomPint;
+        Off++;
+        size_t l = 12;
+        memcpy(
+            buf + Off,
+            (const unsigned char *)"\x8B\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+            l);
+        Off += l;
+    }
+    {
+        buf[Off] = KEKSAtomPint;
+        Off++;
+        size_t l = 18;
+        memcpy(
+            buf + Off,
+            (const unsigned char
+                 *)"\x91\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+            l);
+        Off += l;
+    }
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .ints.pos
 
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .ints
 
-    adder(
-        KEKSAtomStrEncode(&Got, buf + Off, len - Off, (const unsigned char *)"uuid", 4));
+    adder(KEKSAtomStrEncode(
+        &Got, buf + Off, len - Off, (const unsigned char *)"uuid", 4));
     adder(KEKSAtomUUIDEncode(
         &Got,
         buf + Off,
@@ -191,35 +206,41 @@ main(void)
         assert(KEKSTimespecToTAI64(tai, &ts));
         adder(KEKSAtomTAI64Encode(&Got, buf + Off, len - Off, tai, 12));
 
-        adder(KEKSAtomRawEncode(
-            &Got,
-            buf + Off,
-            len - Off,
-            KEKSAtomTAI64N,
-            (const unsigned char *)"\x40\x00\x00\x00\x49\x96\x02\xF4\x00\x06\xF8\x55",
-            12));
-
-        adder(KEKSAtomRawEncode(
-            &Got,
-            buf + Off,
-            len - Off,
-            KEKSAtomTAI64NA,
-            (const unsigned char
-                 *)"\x40\x00\x00\x00\x49\x96\x02\xF4\x00\x06\xF8\x55\x07\x5B\xCD\x15",
-            16));
+        {
+            buf[Off] = KEKSAtomTAI64N;
+            Off++;
+            size_t l = 12;
+            memcpy(
+                buf + Off,
+                (const unsigned char
+                     *)"\x40\x00\x00\x00\x49\x96\x02\xF4\x00\x06\xF8\x55",
+                l);
+            Off += l;
+        }
+        {
+            buf[Off] = KEKSAtomTAI64NA;
+            Off++;
+            size_t l = 16;
+            memcpy(
+                buf + Off,
+                (const unsigned char
+                     *)"\x40\x00\x00\x00\x49\x96\x02\xF4\x00\x06\xF8\x55\x07\x5B\xCD\x15",
+                l);
+            Off += l;
+        }
     }
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .dates
 
     adder(KEKSAtomStrEncode(
         &Got, buf + Off, len - Off, (const unsigned char *)"floats", 6));
     adder(KEKSAtomListEncode(&Got, buf + Off, len - Off)); // .floats
-    adder(KEKSAtomRawEncode(
-        &Got,
-        buf + Off,
-        len - Off,
-        KEKSAtomFloat32,
-        (const unsigned char *)"\x01\x02\x03\x04",
-        4));
+    {
+        buf[Off] = KEKSAtomFloat32;
+        Off++;
+        size_t l = 4;
+        memcpy(buf + Off, (const unsigned char *)"\x01\x02\x03\x04", l);
+        Off += l;
+    }
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .floats
 
     adder(KEKSAtomStrEncode(
@@ -233,13 +254,13 @@ main(void)
     adder(KEKSAtomBinEncode(&Got, buf + Off, len - Off, NULL, 0));
     memset(bin, '\x00', 16);
     adder(KEKSAtomUUIDEncode(&Got, buf + Off, len - Off, bin));
-    adder(KEKSAtomRawEncode(
-        &Got,
-        buf + Off,
-        len - Off,
-        KEKSAtomTAI64,
-        (const unsigned char *)"\x00\x00\x00\x00\x00\x00\x00\x00",
-        8));
+    {
+        buf[Off] = KEKSAtomTAI64;
+        Off++;
+        size_t l = 8;
+        memcpy(buf + Off, (const unsigned char *)"\x00\x00\x00\x00\x00\x00\x00\x00", l);
+        Off += l;
+    }
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .empties
 
     adder(KEKSAtomEOCEncode(&Got, buf + Off, len - Off)); // .
index 8ae2d42cbc497e6d10bbe62a3cdb1016f3f7c9d50869ffc182ec234e4e70c705..c502f688f2966b92107614466a4321c13c4dd26956ce81520aec30b43ca0dab5 100644 (file)
@@ -26,4 +26,3 @@
 @anchor{KEKSAtomChunkEncode}
 @DOCSTRING KEKSAtomChunkEncode@
 @DOCSTRING KEKSAtomTAI64Encode@
-@DOCSTRING KEKSAtomRawEncode@
index 802d4379c4eade8ccaaccbd37fc2dccffa0f23eb9a5e9b5d66979f289416d39a..22d0ae9fe355f2f88931df3b1fa8801d68d15857692b47f522be9ebcc0b1ff61 100644 (file)
@@ -13,6 +13,8 @@
 // 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/>.
 
+#include <assert.h>
+#include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
@@ -36,12 +38,11 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
     if (len < 1) {
         return KEKSErrNotEnough;
     }
-    atom->tag = buf[0];
+    unsigned char tag = buf[0];
 
-    if ((atom->tag & (uint8_t)KEKSAtomStrings) > 0) {
-        atom->typ =
-            ((atom->tag & (uint8_t)KEKSAtomIsUTF8) == 0) ? KEKSItemBin : KEKSItemStr;
-        uint64_t l = atom->tag & (uint8_t)63;
+    if ((tag & (uint8_t)KEKSAtomStrings) > 0) {
+        atom->typ = ((tag & (uint8_t)KEKSAtomIsUTF8) == 0) ? KEKSItemBin : KEKSItemStr;
+        uint64_t l = tag & (uint8_t)63;
         size_t ll = 0;
         switch (l) {
         case 61:
@@ -95,7 +96,7 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
         return KEKSErrNo;
     }
 
-    switch (atom->tag) {
+    switch (tag) {
     case KEKSAtomEOC:
         atom->typ = KEKSItemEOC;
         break;
@@ -139,7 +140,7 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
 
     case KEKSAtomPint:
     case KEKSAtomNint: {
-        atom->typ = (atom->tag == KEKSAtomPint) ? KEKSItemPint : KEKSItemNint;
+        atom->typ = (tag == KEKSAtomPint) ? KEKSItemPint : KEKSItemNint;
         size_t binGot = 0;
         struct KEKSAtom bin;
         memset(&bin, 0, sizeof(struct KEKSAtom));
@@ -167,16 +168,16 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
         }
         if (bin.v.str.len > 8) {
             atom->typ = KEKSItemRaw;
-            atom->v.str.len = binGot;
-            atom->v.str.ptr = buf + 1;
+            atom->v.str.len = binGot + 1;
+            atom->v.str.ptr = buf;
             return KEKSErrNo;
         }
         atom->v.pint = keksFromBE(bin.v.str.ptr, bin.v.str.len);
         if (atom->typ == KEKSItemNint) {
             if (atom->v.pint >= ((uint64_t)1 << (uint8_t)63)) {
                 atom->typ = KEKSItemRaw;
-                atom->v.str.len = binGot;
-                atom->v.str.ptr = buf + 1;
+                atom->v.str.len = binGot + 1;
+                atom->v.str.ptr = buf;
             } else {
                 atom->v.nint = -1 - (int64_t)(atom->v.pint);
             }
@@ -190,7 +191,7 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
     case KEKSAtomFloat128:
     case KEKSAtomFloat256: {
         size_t l = 0;
-        switch (atom->tag) {
+        switch (tag) {
         case KEKSAtomFloat16:
             l = 2;
             break;
@@ -206,6 +207,8 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
         case KEKSAtomFloat256:
             l = 32;
             break;
+        default:
+            assert(false);
         }
         atom->typ = KEKSItemFloat;
         (*got) += l;
@@ -213,8 +216,8 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
             return KEKSErrNotEnough;
         }
         atom->typ = KEKSItemRaw;
-        atom->v.str.len = l;
-        atom->v.str.ptr = buf + 1;
+        atom->v.str.len = l + 1;
+        atom->v.str.ptr = buf;
         break;
     }
 
@@ -222,7 +225,7 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
     case KEKSAtomTAI64N:
     case KEKSAtomTAI64NA: {
         size_t l = 0;
-        switch (atom->tag) {
+        switch (tag) {
         case KEKSAtomTAI64:
             l = 8;
             break;
@@ -232,6 +235,8 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
         case KEKSAtomTAI64NA:
             l = 16;
             break;
+        default:
+            assert(false);
         }
         atom->typ = KEKSItemTAI64;
         (*got) += l;
index 64d3cb445a22da02edddd7b09b7aed18f6bc3559bc3b2fd1aeb99a16d9fb9855..507d48ec479952712fca479388a741b01eba39656dbc622658320239e4f429b9 100644 (file)
@@ -51,9 +51,6 @@ enum KEKSItemType {
 // @deftp {Data type} {struct KEKSAtom}
 // Basic unit of the library, describing single TLV-like value.
 // @table @code
-// @item .tag
-//     Real value of the atom's tag. May be used during debugging or
-//     when constructing raw value.
 // @item .typ
 //     High level @ref{KEKSItemType, type} of the atom's value. As a rule
 //     you should look solely on it.
@@ -99,8 +96,7 @@ struct KEKSAtom {
         } str;
     } v;
     enum KEKSItemType typ;
-    unsigned char tag;
-    char _pad[3];
+    char _pad[4];
 };
 
 // TEXINFO: KEKSAtomDecode
index a1a2456e1c8df1720c26bdd733a26e27462e283d3a961ecbdb476f096030c523..4febb507a4e8de80bf92c477b47a3340e47dfbe5219274ca5579152ae26f76f8 100644 (file)
@@ -274,25 +274,3 @@ KEKSAtomTAI64Encode(
     memcpy(buf + 1, src, srcLen);
     return true;
 }
-
-bool
-KEKSAtomRawEncode(
-    size_t *len,
-    unsigned char *buf,
-    const size_t cap,
-    const unsigned char typ,
-    const unsigned char *src,
-    const size_t srcLen)
-{
-    (*len) = 1 + srcLen;
-    if ((*len) <= srcLen) {
-        (*len) = 0;
-        return false;
-    }
-    if (cap < (*len)) {
-        return false;
-    }
-    buf[0] = typ;
-    memcpy(buf + 1, src, srcLen);
-    return true;
-}
index bb442403c1cbff36dca0f915bd672813515aa1503231be04035e24e3aafea860..c0bd9cad7cf1027b5375d5399a32efc83f58be8074426276565ef344405aed96 100644 (file)
@@ -174,22 +174,4 @@ KEKSAtomTAI64Encode(
     const unsigned char *src,
     const size_t srcLen);
 
-// TEXINFO: KEKSAtomRawEncode
-// @deftypefun bool KEKSAtomRawEncode @
-//     (size_t *len, unsigned char *buf, const size_t cap, @
-//     const unsigned char typ, const unsigned char *src, const size_t srcLen)
-// Encode raw atom in provided @var{buf} with capacity of @var{cap}.
-// In case of success, true is returned and @var{len} will hold how many
-// bytes were written to buffer. It is just a convenient wrapper instead
-// of manual writing of the @code{typ} byte followed by @var{srcLen} bytes.
-// @end deftypefun
-bool
-KEKSAtomRawEncode(
-    size_t *len,
-    unsigned char *buf,
-    const size_t cap,
-    const unsigned char typ,
-    const unsigned char *src,
-    const size_t srcLen);
-
 #endif // KEKS_ENC_H
index c32574a82e2345d34880fc504ac0f6587c5d21808027d6beb6a36f14f38cdcb5..1427249ce5b4c8f3459434f08b3f27d70adac9736fa3510c5374450969f38292 100644 (file)
@@ -422,13 +422,12 @@ KEKSItemsEncode( // NOLINT(misc-no-recursion)
             &got, buf + *off, cap - (*off), item->atom.v.str.ptr, item->atom.v.str.len);
         break;
     case KEKSItemRaw:
-        ok = KEKSAtomRawEncode(
-            &got,
-            buf + *off,
-            cap - (*off),
-            item->atom.tag,
-            item->atom.v.str.ptr,
-            item->atom.v.str.len);
+        if ((cap - (*off)) < item->atom.v.str.len) {
+            return false;
+        }
+        memcpy(buf + *off, item->atom.v.str.ptr, item->atom.v.str.len);
+        ok = true;
+        (*off) += item->atom.v.str.len;
         break;
     default:
         return false;
diff --git a/go/cmd/iter-print/main.go b/go/cmd/iter-print/main.go
deleted file mode 100644 (file)
index ffce5cb..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-// GoKEKS -- Go KEKS codec implementation
-// 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 (
-       "bufio"
-       "encoding/hex"
-       "fmt"
-       "log"
-       "os"
-       "strings"
-       "time"
-
-       "go.cypherpunks.su/keks"
-       "go.cypherpunks.su/keks/types"
-)
-
-func prindent(depth int) {
-       fmt.Print(strings.Repeat("  ", depth))
-}
-
-func printer(iter *keks.Iterator, count int, inList, inMap bool) {
-       for i := 0; i < count; i++ {
-               if !iter.Next() {
-                       panic("unexpected")
-               }
-               depth := iter.Depth
-               prindent(depth)
-               if inList {
-                       fmt.Printf("%d: ", i)
-               } else if inMap {
-                       fmt.Print(iter.Str())
-                       fmt.Print(": ")
-                       if !iter.Next() {
-                               panic("unexpected")
-                       }
-               }
-               switch iter.T {
-               case types.List:
-                       fmt.Printf("[ %d\n", iter.Len())
-                       printer(iter, iter.Len(), true, false)
-                       prindent(depth)
-                       fmt.Println("]")
-               case types.Map:
-                       fmt.Printf("{ %d\n", iter.Len())
-                       printer(iter, iter.Len(), false, true)
-                       prindent(depth)
-                       fmt.Println("}")
-
-               case types.NIL:
-                       fmt.Println("NIL")
-               case types.Bool:
-                       if iter.Bool() {
-                               fmt.Println("TRUE")
-                       } else {
-                               fmt.Println("FALSE")
-                       }
-               case types.UUID:
-                       fmt.Println(iter.UUID())
-               case types.UInt:
-                       fmt.Println(iter.UInt())
-               case types.Int:
-                       fmt.Println(iter.Int())
-               case types.BigInt:
-                       fmt.Println(iter.BigInt())
-               case types.Blob:
-                       blob := iter.Blob()
-                       fmt.Printf("BLOB[ %d l=%d\n", len(blob.Chunks), blob.ChunkLen)
-                       for i, chunk := range blob.Chunks {
-                               fmt.Print(strings.Repeat("  ", iter.Depth+1))
-                               fmt.Printf("%d: %d:%s\n",
-                                       i, len(chunk), hex.EncodeToString([]byte(chunk)))
-                       }
-               case types.TAI64:
-                       t := iter.TAI64()
-                       fmt.Printf("%s TAI\n", t.Time().Format(time.DateTime))
-               case types.TAI64N:
-                       t := iter.TAI64N()
-                       fmt.Printf("%s TAI\n", t.Time().Format(time.DateTime+".000000000"))
-               case types.TAI64NA:
-                       t := iter.TAI64NA()
-                       fmt.Printf("TAI64NA[%s]\n", hex.EncodeToString(t[:]))
-               case types.Bin:
-                       s := iter.Bin()
-                       fmt.Printf("%d:%s\n", len(s), hex.EncodeToString([]byte(s)))
-               case types.Str:
-                       fmt.Print(`"`)
-                       fmt.Print(iter.Str())
-                       fmt.Println(`"`)
-               case types.Raw:
-                       fmt.Printf("RAW[%s]\n", hex.EncodeToString(iter.Raw()))
-               default:
-                       fmt.Println("???")
-               }
-       }
-}
-
-func main() {
-       ctx := keks.NewDecoderFromReader(bufio.NewReader(os.Stdin), nil)
-       _, err := ctx.Parse()
-       if err != nil {
-               log.Fatal(err)
-       }
-       iter := ctx.Iter()
-       printer(iter, 1, false, false)
-}
diff --git a/go/cmd/print/colour.go b/go/cmd/print/colour.go
new file mode 100644 (file)
index 0000000..85ca085
--- /dev/null
@@ -0,0 +1,35 @@
+package main
+
+import (
+       "bytes"
+       "os"
+
+       "golang.org/x/term"
+)
+
+var (
+       Yellow  string
+       Green   string
+       Blue    string
+       Cyan    string
+       Red     string
+       Magenta string
+       White   string
+       Reset   string
+)
+
+func init() {
+       if os.Getenv("NO_COLOR") != "" {
+               return
+       }
+       var b bytes.Buffer
+       t := term.NewTerminal(&b, "")
+       Yellow = string(t.Escape.Yellow)
+       Green = string(t.Escape.Green)
+       Blue = string(t.Escape.Blue)
+       Cyan = string(t.Escape.Cyan)
+       Red = string(t.Escape.Red)
+       Magenta = string(t.Escape.Magenta)
+       White = string(t.Escape.White)
+       Reset = string(t.Escape.Reset)
+}
index 78f4ce92ecf82744b3d582790036526fc2cf8170d7e82b6397ce8cc97d1360ae..7b308c3cb1b45146d9cfb303e4ceb8fae2e2d5709095b1afcfd8c04f980a8a2a 100644 (file)
+// GoKEKS -- Go KEKS codec implementation
+// 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 (
        "bufio"
+       "encoding/hex"
+       "flag"
        "fmt"
        "log"
        "os"
+       "strconv"
+       "strings"
+       "time"
 
        "go.cypherpunks.su/keks"
+       "go.cypherpunks.su/keks/types"
+       "go.cypherpunks.su/tai64n/v4"
 )
 
+var MaxStrLen = flag.Uint("max-str-len", 1<<62, "Maximal string length to print")
+
+func prindent(depth int) {
+       fmt.Print(strings.Repeat("  ", depth))
+}
+
+func hexenc(b []byte) string {
+       return strings.ToUpper(hex.EncodeToString(b))
+}
+
+func printer(iter *keks.Iterator, count int, inList, inMap bool) {
+       for i := 0; i < count; i++ {
+               if !iter.Next() {
+                       panic("unexpected")
+               }
+               depth := iter.Depth
+               fmt.Print(Blue + strconv.Itoa(depth) + 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")
+                       }
+               }
+               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(" ]")
+               case types.Map:
+                       fmt.Printf("{ %s%d%s\n", Cyan, iter.Len(), Reset)
+                       printer(iter, iter.Len(), false, true)
+                       prindent(depth)
+                       fmt.Println(" }")
+
+               case types.NIL:
+                       fmt.Println("NIL")
+               case types.Bool:
+                       if iter.Bool() {
+                               fmt.Println("TRUE")
+                       } else {
+                               fmt.Println("FALSE")
+                       }
+               case types.UUID:
+                       fmt.Println(iter.UUID())
+               case types.UInt:
+                       fmt.Println(iter.UInt())
+               case types.Int:
+                       fmt.Println(iter.Int())
+               case types.BigInt:
+                       fmt.Println(iter.BigInt())
+               case types.Blob:
+                       blob := iter.Blob()
+                       fmt.Printf("BLOB[ %s%d l=%d%s\n", Cyan, len(blob.Chunks), blob.ChunkLen, Reset)
+                       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)))
+                       }
+               case types.TAI64:
+                       t := iter.TAI64().Time()
+                       utc, isLeap := tai64n.Leapsecs.Sub(t)
+                       if isLeap {
+                               fmt.Printf("TAI64(%s TAI, leap)\n", t.Format(time.DateTime))
+                       } else {
+                               fmt.Printf("TAI64(%s TAI, %s UTC)\n",
+                                       t.Format(time.DateTime), utc.Format(time.DateTime))
+                       }
+               case types.TAI64N:
+                       t := iter.TAI64N().Time()
+                       utc, isLeap := tai64n.Leapsecs.Sub(t)
+                       if isLeap {
+                               fmt.Printf("TAI64N(%s TAI, leap)\n",
+                                       t.Format(time.DateTime+".000000000"))
+                       } else {
+                               fmt.Printf("TAI64N(%s TAI, %s UTC)\n",
+                                       t.Format(time.DateTime+".000000000"),
+                                       utc.Format(time.DateTime+".000000000"))
+                       }
+               case types.TAI64NA:
+                       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)
+               case types.Str:
+                       fmt.Print(`"`)
+                       s := iter.Str()
+                       if len(s) > int(*MaxStrLen) {
+                               fmt.Print(s[:int(*MaxStrLen)])
+                               fmt.Print("...")
+                       } else {
+                               fmt.Print(s)
+                       }
+                       fmt.Println(`"`)
+               case types.Raw:
+                       fmt.Printf("(l=%d v=%s)\n", len(iter.Raw()), hexenc(iter.Raw()))
+               default:
+                       fmt.Println("???")
+               }
+       }
+}
+
 func main() {
-       decoder := keks.NewDecoderFromReader(bufio.NewReader(os.Stdin), nil)
-       v, err := decoder.Decode()
+       flag.Parse()
+       ctx := keks.NewDecoderFromReader(bufio.NewReader(os.Stdin), nil)
+       _, err := ctx.Parse()
        if err != nil {
                log.Fatal(err)
        }
-       fmt.Printf("%v\n%d bytes\n", v, decoder.Read)
+       iter := ctx.Iter()
+       printer(iter, 1, false, false)
+       fmt.Println(ctx.Read, "bytes")
 }
index e1b4cc904e54d4b2e6267d2dfde56de9065afd375d2645cb2ad92756bbfb6dca..aab08133f50eb50accfd6fa99c3dbca6052caa8210960a292f0cf9cab8701a00 100644 (file)
--- a/go/go.mod
+++ b/go/go.mod
@@ -8,3 +8,8 @@ require (
        github.com/google/uuid v1.6.0
        github.com/mitchellh/mapstructure v1.5.0
 )
+
+require (
+       golang.org/x/sys v0.28.0 // indirect
+       golang.org/x/term v0.27.0 // indirect
+)
index 063c682ef8bc10d607af9505018ff485e66d94e8febb95a5a280ac024547ac33..6790579f6397a3031b924681d5bc13d7b277fdcc855d63d141821ec24630f805 100644 (file)
--- a/go/go.sum
+++ b/go/go.sum
@@ -4,3 +4,7 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 go.cypherpunks.su/tai64n/v4 v4.1.0 h1:jW0EyklKXpSy9DSFMcDbu7XuLlMkn6kkpNWiMG6UT5c=
 go.cypherpunks.su/tai64n/v4 v4.1.0/go.mod h1:/uKUdhLOy8UciRKpapPaFXSOoa/SiXjs3XsDDpAz7OA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=