#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)
{
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"
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;
}
#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};
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;
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;
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) {
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;
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);
}
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:
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'},
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])) {
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));
}
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:
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
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(
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(
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,
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(
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)); // .
@anchor{KEKSAtomChunkEncode}
@DOCSTRING KEKSAtomChunkEncode@
@DOCSTRING KEKSAtomTAI64Encode@
-@DOCSTRING KEKSAtomRawEncode@
// 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>
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:
return KEKSErrNo;
}
- switch (atom->tag) {
+ switch (tag) {
case KEKSAtomEOC:
atom->typ = KEKSItemEOC;
break;
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));
}
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);
}
case KEKSAtomFloat128:
case KEKSAtomFloat256: {
size_t l = 0;
- switch (atom->tag) {
+ switch (tag) {
case KEKSAtomFloat16:
l = 2;
break;
case KEKSAtomFloat256:
l = 32;
break;
+ default:
+ assert(false);
}
atom->typ = KEKSItemFloat;
(*got) += l;
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;
}
case KEKSAtomTAI64N:
case KEKSAtomTAI64NA: {
size_t l = 0;
- switch (atom->tag) {
+ switch (tag) {
case KEKSAtomTAI64:
l = 8;
break;
case KEKSAtomTAI64NA:
l = 16;
break;
+ default:
+ assert(false);
}
atom->typ = KEKSItemTAI64;
(*got) += l;
// @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.
} str;
} v;
enum KEKSItemType typ;
- unsigned char tag;
- char _pad[3];
+ char _pad[4];
};
// TEXINFO: KEKSAtomDecode
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;
-}
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
&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;
+++ /dev/null
-// 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)
-}
--- /dev/null
+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)
+}
+// 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")
}
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
+)
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=