koffi 2.14.0 → 2.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +1 -1
  3. package/build/koffi/darwin_arm64/koffi.node +0 -0
  4. package/build/koffi/darwin_x64/koffi.node +0 -0
  5. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  6. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  7. package/build/koffi/freebsd_x64/koffi.node +0 -0
  8. package/build/koffi/linux_arm64/koffi.node +0 -0
  9. package/build/koffi/linux_armhf/koffi.node +0 -0
  10. package/build/koffi/linux_ia32/koffi.node +0 -0
  11. package/build/koffi/linux_loong64/koffi.node +0 -0
  12. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  13. package/build/koffi/linux_x64/koffi.node +0 -0
  14. package/build/koffi/musl_arm64/koffi.node +0 -0
  15. package/build/koffi/musl_x64/koffi.node +0 -0
  16. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  17. package/build/koffi/openbsd_x64/koffi.node +0 -0
  18. package/build/koffi/win32_arm64/koffi.node +0 -0
  19. package/build/koffi/win32_ia32/koffi.node +0 -0
  20. package/build/koffi/win32_x64/koffi.node +0 -0
  21. package/doc/pages/index.md +43 -4
  22. package/doc/pages/platforms.md +8 -19
  23. package/doc/pages.ini +0 -7
  24. package/doc/static/perf_windows.png +0 -0
  25. package/index.js +3 -2
  26. package/indirect.js +3 -2
  27. package/package.json +3 -2
  28. package/src/cnoke/src/builder.js +1 -2
  29. package/src/core/base/base.cc +791 -555
  30. package/src/core/base/base.hh +577 -450
  31. package/src/core/base/crc.inc +1 -1
  32. package/src/core/base/crc_gen.py +1 -1
  33. package/src/core/base/unicode.inc +1 -1
  34. package/src/core/base/unicode_gen.py +1 -1
  35. package/src/koffi/src/abi_arm32.cc +24 -24
  36. package/src/koffi/src/abi_arm64.cc +29 -29
  37. package/src/koffi/src/abi_riscv64.cc +27 -27
  38. package/src/koffi/src/abi_x64_sysv.cc +29 -29
  39. package/src/koffi/src/abi_x64_win.cc +20 -20
  40. package/src/koffi/src/abi_x86.cc +26 -26
  41. package/src/koffi/src/call.cc +82 -236
  42. package/src/koffi/src/call.hh +6 -6
  43. package/src/koffi/src/ffi.cc +60 -60
  44. package/src/koffi/src/ffi.hh +9 -9
  45. package/src/koffi/src/parser.cc +2 -2
  46. package/src/koffi/src/parser.hh +1 -1
  47. package/src/koffi/src/trampolines/prototypes.inc +1 -1
  48. package/src/koffi/src/util.cc +43 -43
  49. package/src/koffi/src/util.hh +5 -5
  50. package/src/koffi/src/win32.cc +5 -5
  51. package/src/koffi/src/win32.hh +1 -1
@@ -133,7 +133,7 @@
133
133
  #include <random>
134
134
  #include <thread>
135
135
 
136
- namespace RG {
136
+ namespace K {
137
137
 
138
138
  // ------------------------------------------------------------------------
139
139
  // Utility
@@ -141,7 +141,7 @@ namespace RG {
141
141
 
142
142
  #if !defined(FELIX)
143
143
  #if defined(FELIX_TARGET)
144
- const char *FelixTarget = RG_STRINGIFY(FELIX_TARGET);
144
+ const char *FelixTarget = K_STRINGIFY(FELIX_TARGET);
145
145
  #else
146
146
  const char *FelixTarget = "????";
147
147
  #endif
@@ -158,8 +158,8 @@ extern "C" void AssertMessage(const char *filename, int line, const char *cond)
158
158
 
159
159
  void *MemMem(const void *src, Size src_len, const void *needle, Size needle_len)
160
160
  {
161
- RG_ASSERT(src_len >= 0);
162
- RG_ASSERT(needle_len > 0);
161
+ K_ASSERT(src_len >= 0);
162
+ K_ASSERT(needle_len > 0);
163
163
 
164
164
  src_len -= needle_len - 1;
165
165
 
@@ -195,7 +195,7 @@ protected:
195
195
  void *Allocate(Size size, unsigned int flags) override
196
196
  {
197
197
  void *ptr = malloc((size_t)size);
198
- RG_CRITICAL(ptr, "Failed to allocate %1 of memory", FmtMemSize(size));
198
+ K_CRITICAL(ptr, "Failed to allocate %1 of memory", FmtMemSize(size));
199
199
 
200
200
  if (flags & (int)AllocFlag::Zero) {
201
201
  MemSet(ptr, 0, size);
@@ -211,7 +211,7 @@ protected:
211
211
  ptr = nullptr;
212
212
  } else {
213
213
  void *new_ptr = realloc(ptr, (size_t)new_size);
214
- RG_CRITICAL(new_ptr || !new_size, "Failed to resize %1 memory block to %2",
214
+ K_CRITICAL(new_ptr || !new_size, "Failed to resize %1 memory block to %2",
215
215
  FmtMemSize(old_size), FmtMemSize(new_size));
216
216
 
217
217
  if ((flags & (int)AllocFlag::Zero) && new_size > old_size) {
@@ -232,14 +232,14 @@ protected:
232
232
 
233
233
  class NullAllocator: public Allocator {
234
234
  protected:
235
- void *Allocate(Size, unsigned int) override { RG_UNREACHABLE(); }
236
- void *Resize(void *, Size, Size, unsigned int) override { RG_UNREACHABLE(); }
235
+ void *Allocate(Size, unsigned int) override { K_UNREACHABLE(); }
236
+ void *Resize(void *, Size, Size, unsigned int) override { K_UNREACHABLE(); }
237
237
  void Release(const void *, Size) override {}
238
238
  };
239
239
 
240
240
  Allocator *GetDefaultAllocator()
241
241
  {
242
- static Allocator *default_allocator = new RG_DEFAULT_ALLOCATOR;
242
+ static Allocator *default_allocator = new K_DEFAULT_ALLOCATOR;
243
243
  return default_allocator;
244
244
  }
245
245
 
@@ -276,7 +276,7 @@ void LinkedAllocator::ReleaseAll()
276
276
 
277
277
  void LinkedAllocator::ReleaseAllExcept(void *ptr)
278
278
  {
279
- RG_ASSERT(ptr);
279
+ K_ASSERT(ptr);
280
280
 
281
281
  Bucket *keep = PointerToBucket(ptr);
282
282
  Bucket *bucket = keep->next;
@@ -295,7 +295,7 @@ void LinkedAllocator::ReleaseAllExcept(void *ptr)
295
295
 
296
296
  void *LinkedAllocator::Allocate(Size size, unsigned int flags)
297
297
  {
298
- Bucket *bucket = (Bucket *)AllocateRaw(allocator, RG_SIZE(Bucket) + size, flags);
298
+ Bucket *bucket = (Bucket *)AllocateRaw(allocator, K_SIZE(Bucket) + size, flags);
299
299
 
300
300
  bucket->prev = bucket;
301
301
  bucket->next = bucket;
@@ -321,8 +321,8 @@ void *LinkedAllocator::Resize(void *ptr, Size old_size, Size new_size, unsigned
321
321
  Bucket *bucket = PointerToBucket(ptr);
322
322
  bool single = (bucket->next == bucket);
323
323
 
324
- bucket = (Bucket *)ResizeRaw(allocator, bucket, RG_SIZE(Bucket) + old_size,
325
- RG_SIZE(Bucket) + new_size, flags);
324
+ bucket = (Bucket *)ResizeRaw(allocator, bucket, K_SIZE(Bucket) + old_size,
325
+ K_SIZE(Bucket) + new_size, flags);
326
326
 
327
327
  list = bucket;
328
328
 
@@ -353,7 +353,7 @@ void LinkedAllocator::Release(const void *ptr, Size size)
353
353
  bucket->prev->next = bucket->next;
354
354
  bucket->next->prev = bucket->prev;
355
355
 
356
- ReleaseRaw(allocator, bucket, RG_SIZE(Bucket) + size);
356
+ ReleaseRaw(allocator, bucket, K_SIZE(Bucket) + size);
357
357
  }
358
358
 
359
359
  void LinkedAllocator::GiveTo(LinkedAllocator *alloc)
@@ -366,7 +366,7 @@ void LinkedAllocator::GiveTo(LinkedAllocator *alloc)
366
366
  list->next = other;
367
367
  other->prev = list;
368
368
  } else if (list) {
369
- RG_ASSERT(!alloc->list);
369
+ K_ASSERT(!alloc->list);
370
370
  alloc->list = list;
371
371
  }
372
372
 
@@ -415,7 +415,7 @@ void BlockAllocator::ReleaseAll()
415
415
 
416
416
  void *BlockAllocator::Allocate(Size size, unsigned int flags)
417
417
  {
418
- RG_ASSERT(size >= 0);
418
+ K_ASSERT(size >= 0);
419
419
 
420
420
  // Keep alignement requirements
421
421
  Size aligned_size = AlignLen(size, 8);
@@ -425,7 +425,7 @@ void *BlockAllocator::Allocate(Size size, unsigned int flags)
425
425
  return ptr;
426
426
  } else {
427
427
  if (!current_bucket || (current_bucket->used + aligned_size) > block_size) {
428
- current_bucket = (Bucket *)AllocateRaw(&allocator, RG_SIZE(Bucket) + block_size,
428
+ current_bucket = (Bucket *)AllocateRaw(&allocator, K_SIZE(Bucket) + block_size,
429
429
  flags & ~(int)AllocFlag::Zero);
430
430
  current_bucket->used = 0;
431
431
  }
@@ -444,8 +444,8 @@ void *BlockAllocator::Allocate(Size size, unsigned int flags)
444
444
 
445
445
  void *BlockAllocator::Resize(void *ptr, Size old_size, Size new_size, unsigned int flags)
446
446
  {
447
- RG_ASSERT(old_size >= 0);
448
- RG_ASSERT(new_size >= 0);
447
+ K_ASSERT(old_size >= 0);
448
+ K_ASSERT(new_size >= 0);
449
449
 
450
450
  if (!new_size) {
451
451
  Release(ptr, old_size);
@@ -492,7 +492,7 @@ void *BlockAllocator::Resize(void *ptr, Size old_size, Size new_size, unsigned i
492
492
 
493
493
  void BlockAllocator::Release(const void *ptr, Size size)
494
494
  {
495
- RG_ASSERT(size >= 0);
495
+ K_ASSERT(size >= 0);
496
496
 
497
497
  if (ptr) {
498
498
  Size aligned_size = AlignLen(size, 8);
@@ -501,7 +501,7 @@ void BlockAllocator::Release(const void *ptr, Size size)
501
501
  current_bucket->used -= aligned_size;
502
502
 
503
503
  if (!current_bucket->used) {
504
- ReleaseRaw(&allocator, current_bucket, RG_SIZE(Bucket) + block_size);
504
+ ReleaseRaw(&allocator, current_bucket, K_SIZE(Bucket) + block_size);
505
505
  current_bucket = nullptr;
506
506
  }
507
507
 
@@ -618,7 +618,7 @@ void ZeroSafe(void *ptr, Size len)
618
618
 
619
619
  LocalDate LocalDate::FromJulianDays(int days)
620
620
  {
621
- RG_ASSERT(days >= 0);
621
+ K_ASSERT(days >= 0);
622
622
 
623
623
  // Algorithm from Richards, copied from Wikipedia:
624
624
  // https://en.wikipedia.org/w/index.php?title=Julian_day&oldid=792497863
@@ -639,7 +639,7 @@ LocalDate LocalDate::FromJulianDays(int days)
639
639
 
640
640
  int LocalDate::ToJulianDays() const
641
641
  {
642
- RG_ASSERT(IsValid());
642
+ K_ASSERT(IsValid());
643
643
 
644
644
  // Straight from the Web:
645
645
  // http://www.cs.utsa.edu/~cs1063/projects/Spring2011/Project1/jdn-explanation.html
@@ -659,7 +659,7 @@ int LocalDate::ToJulianDays() const
659
659
 
660
660
  int LocalDate::GetWeekDay() const
661
661
  {
662
- RG_ASSERT(IsValid());
662
+ K_ASSERT(IsValid());
663
663
 
664
664
  // Zeller's congruence:
665
665
  // https://en.wikipedia.org/wiki/Zeller%27s_congruence
@@ -684,7 +684,7 @@ int LocalDate::GetWeekDay() const
684
684
 
685
685
  LocalDate &LocalDate::operator++()
686
686
  {
687
- RG_ASSERT(IsValid());
687
+ K_ASSERT(IsValid());
688
688
 
689
689
  if (st.day < DaysInMonth(st.year, st.month)) {
690
690
  st.day++;
@@ -702,7 +702,7 @@ LocalDate &LocalDate::operator++()
702
702
 
703
703
  LocalDate &LocalDate::operator--()
704
704
  {
705
- RG_ASSERT(IsValid());
705
+ K_ASSERT(IsValid());
706
706
 
707
707
  if (st.day > 1) {
708
708
  st.day--;
@@ -754,13 +754,13 @@ int64_t GetUnixTime()
754
754
  return (int64_t)emscripten_get_now();
755
755
  #elif defined(__linux__)
756
756
  struct timespec ts;
757
- RG_CRITICAL(clock_gettime(CLOCK_REALTIME_COARSE, &ts) == 0, "clock_gettime(CLOCK_REALTIME_COARSE) failed: %1", strerror(errno));
757
+ K_CRITICAL(clock_gettime(CLOCK_REALTIME_COARSE, &ts) == 0, "clock_gettime(CLOCK_REALTIME_COARSE) failed: %1", strerror(errno));
758
758
 
759
759
  int64_t time = (int64_t)ts.tv_sec * 1000 + (int64_t)ts.tv_nsec / 1000000;
760
760
  return time;
761
761
  #else
762
762
  struct timespec ts;
763
- RG_CRITICAL(clock_gettime(CLOCK_REALTIME, &ts) == 0, "clock_gettime(CLOCK_REALTIME) failed: %1", strerror(errno));
763
+ K_CRITICAL(clock_gettime(CLOCK_REALTIME, &ts) == 0, "clock_gettime(CLOCK_REALTIME) failed: %1", strerror(errno));
764
764
 
765
765
  int64_t time = (int64_t)ts.tv_sec * 1000 + (int64_t)ts.tv_nsec / 1000000;
766
766
  return time;
@@ -775,12 +775,12 @@ int64_t GetMonotonicTime()
775
775
  return (int64_t)emscripten_get_now();
776
776
  #elif defined(CLOCK_MONOTONIC_COARSE)
777
777
  struct timespec ts;
778
- RG_CRITICAL(clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0, "clock_gettime(CLOCK_MONOTONIC_COARSE) failed: %1", strerror(errno));
778
+ K_CRITICAL(clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0, "clock_gettime(CLOCK_MONOTONIC_COARSE) failed: %1", strerror(errno));
779
779
 
780
780
  return (int64_t)ts.tv_sec * 1000 + (int64_t)ts.tv_nsec / 1000000;
781
781
  #else
782
782
  struct timespec ts;
783
- RG_CRITICAL(clock_gettime(CLOCK_MONOTONIC, &ts) == 0, "clock_gettime(CLOCK_MONOTONIC) failed: %1", strerror(errno));
783
+ K_CRITICAL(clock_gettime(CLOCK_MONOTONIC, &ts) == 0, "clock_gettime(CLOCK_MONOTONIC) failed: %1", strerror(errno));
784
784
 
785
785
  return (int64_t)ts.tv_sec * 1000 + (int64_t)ts.tv_nsec / 1000000;
786
786
  #endif
@@ -856,7 +856,7 @@ TimeSpec DecomposeTimeLocal(int64_t time)
856
856
 
857
857
  int64_t ComposeTimeUTC(const TimeSpec &spec)
858
858
  {
859
- RG_ASSERT(!spec.offset);
859
+ K_ASSERT(!spec.offset);
860
860
 
861
861
  struct tm ti = {};
862
862
 
@@ -885,8 +885,8 @@ int64_t ComposeTimeUTC(const TimeSpec &spec)
885
885
 
886
886
  bool CopyString(const char *str, Span<char> buf)
887
887
  {
888
- #if defined(RG_DEBUG)
889
- RG_ASSERT(buf.len > 0);
888
+ #if defined(K_DEBUG)
889
+ K_ASSERT(buf.len > 0);
890
890
  #else
891
891
  if (!buf.len) [[unlikely]]
892
892
  return false;
@@ -907,8 +907,8 @@ bool CopyString(const char *str, Span<char> buf)
907
907
 
908
908
  bool CopyString(Span<const char> str, Span<char> buf)
909
909
  {
910
- #if defined(RG_DEBUG)
911
- RG_ASSERT(buf.len > 0);
910
+ #if defined(K_DEBUG)
911
+ K_ASSERT(buf.len > 0);
912
912
  #else
913
913
  if (!buf.len) [[unlikely]]
914
914
  return false;
@@ -924,7 +924,7 @@ bool CopyString(Span<const char> str, Span<char> buf)
924
924
 
925
925
  Span<char> DuplicateString(Span<const char> str, Allocator *alloc)
926
926
  {
927
- RG_ASSERT(alloc);
927
+ K_ASSERT(alloc);
928
928
 
929
929
  char *new_str = (char *)AllocateRaw(alloc, str.len + 1);
930
930
  MemCpy(new_str, str.ptr, str.len);
@@ -932,23 +932,6 @@ Span<char> DuplicateString(Span<const char> str, Allocator *alloc)
932
932
  return MakeSpan(new_str, str.len);
933
933
  }
934
934
 
935
- bool IsValidUtf8(Span<const char> str)
936
- {
937
- Size i = 0;
938
-
939
- while (i < str.len) {
940
- int32_t uc;
941
- Size bytes = DecodeUtf8(str, i, &uc);
942
-
943
- if (!bytes) [[unlikely]]
944
- return false;
945
-
946
- i += bytes;
947
- }
948
-
949
- return i == str.len;
950
- }
951
-
952
935
  // ------------------------------------------------------------------------
953
936
  // Format
954
937
  // ------------------------------------------------------------------------
@@ -1035,7 +1018,7 @@ static Span<char> FormatUnsignedToSmallHex(uint64_t value, char out_buf[32])
1035
1018
  #if defined(JKJ_HEADER_DRAGONBOX)
1036
1019
  static Size FakeFloatPrecision(Span<char> buf, int K, int min_prec, int max_prec, int *out_K)
1037
1020
  {
1038
- RG_ASSERT(min_prec >= 0);
1021
+ K_ASSERT(min_prec >= 0);
1039
1022
 
1040
1023
  if (-K < min_prec) {
1041
1024
  int delta = min_prec + K;
@@ -1398,7 +1381,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1398
1381
  } break;
1399
1382
 
1400
1383
  case FmtType::Date: {
1401
- RG_ASSERT(!arg.u.date.value || arg.u.date.IsValid());
1384
+ K_ASSERT(!arg.u.date.value || arg.u.date.IsValid());
1402
1385
 
1403
1386
  int year = arg.u.date.st.year;
1404
1387
  if (year < 0) {
@@ -1486,7 +1469,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1486
1469
  static const char *const DefaultChars = "abcdefghijklmnopqrstuvwxyz0123456789";
1487
1470
  Span<const char> chars = arg.u.random.chars ? arg.u.random.chars : DefaultChars;
1488
1471
 
1489
- RG_ASSERT(arg.u.random.len <= RG_SIZE(out_buf.data));
1472
+ K_ASSERT(arg.u.random.len <= K_SIZE(out_buf.data));
1490
1473
 
1491
1474
  for (Size j = 0; j < arg.u.random.len; j++) {
1492
1475
  int rnd = GetRandomInt(0, (int)chars.len);
@@ -1537,9 +1520,9 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1537
1520
  switch (arg.u.span.type) {
1538
1521
  case FmtType::Str1: { arg2.u.str1 = *(const char **)ptr; } break;
1539
1522
  case FmtType::Str2: { arg2.u.str2 = *(const Span<const char> *)ptr; } break;
1540
- case FmtType::Buffer: { RG_UNREACHABLE(); } break;
1523
+ case FmtType::Buffer: { K_UNREACHABLE(); } break;
1541
1524
  case FmtType::Char: { arg2.u.ch = *(const char *)ptr; } break;
1542
- case FmtType::Custom: { RG_UNREACHABLE(); } break;
1525
+ case FmtType::Custom: { K_UNREACHABLE(); } break;
1543
1526
  case FmtType::Bool: { arg2.u.b = *(const bool *)ptr; } break;
1544
1527
  case FmtType::Integer:
1545
1528
  case FmtType::Unsigned:
@@ -1552,7 +1535,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1552
1535
  case 4: { arg2.u.u = *(const uint32_t *)ptr; } break;
1553
1536
  case 2: { arg2.u.u = *(const uint16_t *)ptr; } break;
1554
1537
  case 1: { arg2.u.u = *(const uint8_t *)ptr; } break;
1555
- default: { RG_UNREACHABLE(); } break;
1538
+ default: { K_UNREACHABLE(); } break;
1556
1539
  }
1557
1540
  } break;
1558
1541
  case FmtType::Float: {
@@ -1570,10 +1553,10 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1570
1553
  case FmtType::Date: { arg2.u.date = *(const LocalDate *)ptr; } break;
1571
1554
  case FmtType::TimeISO:
1572
1555
  case FmtType::TimeNice: { arg2.u.time = *(decltype(FmtArg::u.time) *)ptr; } break;
1573
- case FmtType::Random: { RG_UNREACHABLE(); } break;
1574
- case FmtType::FlagNames: { RG_UNREACHABLE(); } break;
1575
- case FmtType::FlagOptions: { RG_UNREACHABLE(); } break;
1576
- case FmtType::Span: { RG_UNREACHABLE(); } break;
1556
+ case FmtType::Random: { K_UNREACHABLE(); } break;
1557
+ case FmtType::FlagNames: { K_UNREACHABLE(); } break;
1558
+ case FmtType::FlagOptions: { K_UNREACHABLE(); } break;
1559
+ case FmtType::Span: { K_UNREACHABLE(); } break;
1577
1560
  }
1578
1561
  ptr += arg.u.span.type_len;
1579
1562
 
@@ -1687,7 +1670,7 @@ static inline Size ProcessAnsiSpecifier(const char *spec, bool vt100, AppendFunc
1687
1670
 
1688
1671
  end:
1689
1672
  if (!valid) {
1690
- #if defined(RG_DEBUG)
1673
+ #if defined(K_DEBUG)
1691
1674
  LogDebug("Format string contains invalid ANSI specifier");
1692
1675
  #endif
1693
1676
  return idx;
@@ -1704,7 +1687,7 @@ end:
1704
1687
  template <typename AppendFunc>
1705
1688
  static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100, AppendFunc append)
1706
1689
  {
1707
- #if defined(RG_DEBUG)
1690
+ #if defined(K_DEBUG)
1708
1691
  bool invalid_marker = false;
1709
1692
  uint32_t unused_arguments = ((uint32_t)1 << args.len) - 1;
1710
1693
  #endif
@@ -1737,7 +1720,7 @@ static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100
1737
1720
  idx--;
1738
1721
  if (idx < args.len) {
1739
1722
  ProcessArg<AppendFunc>(args[idx], append);
1740
- #if defined(RG_DEBUG)
1723
+ #if defined(K_DEBUG)
1741
1724
  unused_arguments &= ~((uint32_t)1 << idx);
1742
1725
  } else {
1743
1726
  invalid_marker = true;
@@ -1748,25 +1731,25 @@ static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100
1748
1731
  append('%');
1749
1732
  fmt_ptr = marker_ptr + 2;
1750
1733
  } else if (marker_ptr[1] == '/') {
1751
- append(*RG_PATH_SEPARATORS);
1734
+ append(*K_PATH_SEPARATORS);
1752
1735
  fmt_ptr = marker_ptr + 2;
1753
1736
  } else if (marker_ptr[1] == '!') {
1754
1737
  fmt_ptr = marker_ptr + 2 + ProcessAnsiSpecifier(marker_ptr + 1, vt100, append);
1755
1738
  } else if (marker_ptr[1]) {
1756
1739
  append(marker_ptr[0]);
1757
1740
  fmt_ptr = marker_ptr + 1;
1758
- #if defined(RG_DEBUG)
1741
+ #if defined(K_DEBUG)
1759
1742
  invalid_marker = true;
1760
1743
  #endif
1761
1744
  } else {
1762
- #if defined(RG_DEBUG)
1745
+ #if defined(K_DEBUG)
1763
1746
  invalid_marker = true;
1764
1747
  #endif
1765
1748
  break;
1766
1749
  }
1767
1750
  }
1768
1751
 
1769
- #if defined(RG_DEBUG)
1752
+ #if defined(K_DEBUG)
1770
1753
  if (invalid_marker && unused_arguments) {
1771
1754
  PrintLn(StdErr, "\nLog format string '%1' has invalid markers and unused arguments", fmt);
1772
1755
  } else if (unused_arguments) {
@@ -1779,7 +1762,7 @@ static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100
1779
1762
 
1780
1763
  Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, Span<char> out_buf)
1781
1764
  {
1782
- RG_ASSERT(out_buf.len >= 0);
1765
+ K_ASSERT(out_buf.len >= 0);
1783
1766
 
1784
1767
  if (!out_buf.len)
1785
1768
  return {};
@@ -1804,7 +1787,7 @@ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, HeapArra
1804
1787
  {
1805
1788
  Size start_len = out_buf->len;
1806
1789
 
1807
- out_buf->Grow(RG_FMT_STRING_BASE_CAPACITY);
1790
+ out_buf->Grow(K_FMT_STRING_BASE_CAPACITY);
1808
1791
  DoFormat(fmt, args, vt100, [&](Span<const char> frag) {
1809
1792
  out_buf->Grow(frag.len + 1);
1810
1793
  MemCpy(out_buf->end(), frag.ptr, frag.len);
@@ -1817,7 +1800,7 @@ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, HeapArra
1817
1800
 
1818
1801
  Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, Allocator *alloc)
1819
1802
  {
1820
- RG_ASSERT(alloc);
1803
+ K_ASSERT(alloc);
1821
1804
 
1822
1805
  HeapArray<char> buf(alloc);
1823
1806
  FmtFmt(fmt, args, vt100, &buf);
@@ -1833,13 +1816,13 @@ void FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, FunctionRef<vo
1833
1816
 
1834
1817
  void PrintFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *st)
1835
1818
  {
1836
- LocalArray<char, RG_FMT_STRING_PRINT_BUFFER_SIZE> buf;
1819
+ LocalArray<char, K_FMT_STRING_PRINT_BUFFER_SIZE> buf;
1837
1820
  DoFormat(fmt, args, st->IsVt100(), [&](Span<const char> frag) {
1838
- if (frag.len > RG_LEN(buf.data) - buf.len) {
1821
+ if (frag.len > K_LEN(buf.data) - buf.len) {
1839
1822
  st->Write(buf);
1840
1823
  buf.len = 0;
1841
1824
  }
1842
- if (frag.len >= RG_LEN(buf.data)) {
1825
+ if (frag.len >= K_LEN(buf.data)) {
1843
1826
  st->Write(frag);
1844
1827
  } else {
1845
1828
  MemCpy(buf.data + buf.len, frag.ptr, frag.len);
@@ -1883,29 +1866,27 @@ void FmtLowerAscii::Format(FunctionRef<void(Span<const char>)> append) const
1883
1866
 
1884
1867
  void FmtEscape::Format(FunctionRef<void(Span<const char>)> append) const
1885
1868
  {
1886
- static const char literals[] = "0123456789ABCDEF";
1887
-
1888
1869
  for (char c: str) {
1889
- if (c >= 32 && (unsigned int)c < 128) {
1890
- append(c);
1870
+ if (c == '"') {
1871
+ append("\\\"");
1872
+ } else if (c == '\'') {
1873
+ append("\\'");
1874
+ } else if (c == '\r') {
1875
+ append("\\r");
1876
+ } else if (c == '\n') {
1877
+ append("\\n");
1878
+ } else if ((unsigned int)c < 32) {
1879
+ char encoded[4];
1880
+
1881
+ encoded[0] = '\\';
1882
+ encoded[1] = '0' + (((uint8_t)c >> 6) & 7);
1883
+ encoded[2] = '0' + (((uint8_t)c >> 3) & 7);
1884
+ encoded[3] = '0' + (((uint8_t)c >> 0) & 7);
1885
+
1886
+ Span<const char> buf = MakeSpan(encoded, 4);
1887
+ append(buf);
1891
1888
  } else {
1892
- switch (c) {
1893
- case '\t': { append('\t'); } break;
1894
- case '\r': { append("\r"); } break;
1895
- case '\n': { append("\n"); } break;
1896
-
1897
- default: {
1898
- char encoded[4];
1899
-
1900
- encoded[0] = '\\';
1901
- encoded[1] = 'x';
1902
- encoded[2] = literals[((uint8_t)c >> 4) & 0xF];
1903
- encoded[3] = literals[((uint8_t)c >> 0) & 0xF];
1904
-
1905
- Span<const char> buf = MakeSpan(encoded, 4);
1906
- append(buf);
1907
- } break;
1908
- }
1889
+ append(c);
1909
1890
  }
1910
1891
  }
1911
1892
  }
@@ -1932,8 +1913,8 @@ void FmtUrlSafe::Format(FunctionRef<void(Span<const char>)> append) const
1932
1913
 
1933
1914
  FmtArg FmtVersion(int64_t version, int parts, int by)
1934
1915
  {
1935
- RG_ASSERT(version >= 0);
1936
- RG_ASSERT(parts > 0);
1916
+ K_ASSERT(version >= 0);
1917
+ K_ASSERT(parts > 0);
1937
1918
 
1938
1919
  FmtArg arg = {};
1939
1920
  arg.type = FmtType::Buffer;
@@ -2019,7 +2000,7 @@ bool GetDebugFlag(const char *name)
2019
2000
 
2020
2001
  if (debug) {
2021
2002
  bool ret = false;
2022
- if (!ParseBool(debug, &ret, RG_DEFAULT_PARSE_FLAGS & ~(int)ParseFlag::Log)) {
2003
+ if (!ParseBool(debug, &ret, K_DEFAULT_PARSE_FLAGS & ~(int)ParseFlag::Log)) {
2023
2004
  LogError("Environment variable '%1' is not a boolean", name);
2024
2005
  }
2025
2006
  return ret;
@@ -2052,7 +2033,7 @@ void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg>
2052
2033
  if (skip)
2053
2034
  return;
2054
2035
  skip = true;
2055
- RG_DEFER { skip = false; };
2036
+ K_DEFER { skip = false; };
2056
2037
 
2057
2038
  if (!init) {
2058
2039
  // Do this first... GetDebugFlag() might log an error or something, in which
@@ -2072,11 +2053,11 @@ void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg>
2072
2053
 
2073
2054
  char msg_buf[2048];
2074
2055
  {
2075
- Size len = FmtFmt(fmt, args, log_vt100, msg_buf).len;
2056
+ Size len = FmtFmt(T(fmt), args, log_vt100, msg_buf).len;
2076
2057
 
2077
- if (len == RG_SIZE(msg_buf) - 1) {
2078
- strncpy(msg_buf + RG_SIZE(msg_buf) - 32, "... [truncated]", 32);
2079
- msg_buf[RG_SIZE(msg_buf) - 1] = 0;
2058
+ if (len == K_SIZE(msg_buf) - 1) {
2059
+ strncpy(msg_buf + K_SIZE(msg_buf) - 32, "... [truncated]", 32);
2060
+ msg_buf[K_SIZE(msg_buf) - 1] = 0;
2080
2061
  }
2081
2062
  }
2082
2063
 
@@ -2105,13 +2086,13 @@ void DefaultLogHandler(LogLevel level, const char *ctx, const char *msg)
2105
2086
 
2106
2087
  void PushLogFilter(const std::function<LogFilterFunc> &func)
2107
2088
  {
2108
- RG_ASSERT(log_filters_len < RG_LEN(log_filters));
2089
+ K_ASSERT(log_filters_len < K_LEN(log_filters));
2109
2090
  log_filters[log_filters_len++] = new std::function<LogFilterFunc>(func);
2110
2091
  }
2111
2092
 
2112
2093
  void PopLogFilter()
2113
2094
  {
2114
- RG_ASSERT(log_filters_len > 0);
2095
+ K_ASSERT(log_filters_len > 0);
2115
2096
  delete log_filters[--log_filters_len];
2116
2097
  }
2117
2098
 
@@ -2119,7 +2100,7 @@ void PopLogFilter()
2119
2100
  bool RedirectLogToWindowsEvents(const char *name)
2120
2101
  {
2121
2102
  static HANDLE log = nullptr;
2122
- RG_ASSERT(!log);
2103
+ K_ASSERT(!log);
2123
2104
 
2124
2105
  log = OpenEventLogA(nullptr, name);
2125
2106
  if (!log) {
@@ -2170,7 +2151,7 @@ bool RedirectLogToWindowsEvents(const char *name)
2170
2151
  #if !defined(__wasi__)
2171
2152
 
2172
2153
  struct ProgressState {
2173
- char text[RG_PROGRESS_TEXT_SIZE];
2154
+ char text[K_PROGRESS_TEXT_SIZE];
2174
2155
 
2175
2156
  int64_t value;
2176
2157
  int64_t min;
@@ -2191,7 +2172,7 @@ struct ProgressNode {
2191
2172
  static std::function<ProgressFunc> pg_handler = DefaultProgressHandler;
2192
2173
 
2193
2174
  static std::atomic_int pg_count;
2194
- static ProgressNode pg_nodes[RG_PROGRESS_MAX_NODES];
2175
+ static ProgressNode pg_nodes[K_PROGRESS_MAX_NODES];
2195
2176
 
2196
2177
  static std::mutex pg_mutex;
2197
2178
  static bool pg_run = false;
@@ -2323,22 +2304,22 @@ ProgressNode *ProgressHandle::AcquireNode()
2323
2304
 
2324
2305
  pg_run = true;
2325
2306
  }
2326
- } else if (count > RG_PROGRESS_USED_NODES) {
2307
+ } else if (count > K_PROGRESS_USED_NODES) {
2327
2308
  pg_count--;
2328
2309
  return nullptr;
2329
2310
  }
2330
2311
 
2331
- int base = GetRandomInt(0, RG_LEN(pg_nodes));
2312
+ int base = GetRandomInt(0, K_LEN(pg_nodes));
2332
2313
 
2333
- for (int i = 0; i < RG_LEN(pg_nodes); i++) {
2334
- int idx = (base + i) % RG_LEN(pg_nodes);
2314
+ for (int i = 0; i < K_LEN(pg_nodes); i++) {
2315
+ int idx = (base + i) % K_LEN(pg_nodes);
2335
2316
 
2336
2317
  ProgressNode *node = &pg_nodes[idx];
2337
2318
  bool used = node->used.exchange(true);
2338
2319
 
2339
2320
  if (!used) {
2340
- static_assert(RG_SIZE(text) == RG_SIZE(node->front.text));
2341
- MemCpy(node->front.text, text, RG_SIZE(text));
2321
+ static_assert(K_SIZE(text) == K_SIZE(node->front.text));
2322
+ MemCpy(node->front.text, text, K_SIZE(text));
2342
2323
 
2343
2324
  ProgressNode *prev = nullptr;
2344
2325
  bool set = this->node.compare_exchange_strong(prev, node);
@@ -2357,16 +2338,16 @@ ProgressNode *ProgressHandle::AcquireNode()
2357
2338
  return nullptr;
2358
2339
  }
2359
2340
 
2360
- void ProgressHandle::CopyText(Span<const char> text, char out[RG_PROGRESS_TEXT_SIZE])
2341
+ void ProgressHandle::CopyText(Span<const char> text, char out[K_PROGRESS_TEXT_SIZE])
2361
2342
  {
2362
- Span<char> buf = MakeSpan(out, RG_PROGRESS_TEXT_SIZE);
2343
+ Span<char> buf = MakeSpan(out, K_PROGRESS_TEXT_SIZE);
2363
2344
  bool complete = CopyString(text, buf);
2364
2345
 
2365
2346
  if (!complete) [[unlikely]] {
2366
- out[RG_PROGRESS_TEXT_SIZE - 4] = '.';
2367
- out[RG_PROGRESS_TEXT_SIZE - 3] = '.';
2368
- out[RG_PROGRESS_TEXT_SIZE - 2] = '.';
2369
- out[RG_PROGRESS_TEXT_SIZE - 1] = 0;
2347
+ out[K_PROGRESS_TEXT_SIZE - 4] = '.';
2348
+ out[K_PROGRESS_TEXT_SIZE - 3] = '.';
2349
+ out[K_PROGRESS_TEXT_SIZE - 2] = '.';
2350
+ out[K_PROGRESS_TEXT_SIZE - 1] = 0;
2370
2351
  }
2371
2352
  }
2372
2353
 
@@ -2491,8 +2472,8 @@ Size ConvertWin32WideToUtf8(LPCWSTR str_w, Span<char> out_str)
2491
2472
  int len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, out_str.ptr, (int)out_str.len - 1, nullptr, nullptr);
2492
2473
  if (!len) {
2493
2474
  switch (GetLastError()) {
2494
- case ERROR_INSUFFICIENT_BUFFER: { LogError("String '<UTF-16 ?>' is too large"); } break;
2495
- case ERROR_NO_UNICODE_TRANSLATION: { LogError("String '<UTF-16 ?>' is not valid UTF-8"); } break;
2475
+ case ERROR_INSUFFICIENT_BUFFER: { LogError("Cannot convert UTF-16 string to UTF-8: too large"); } break;
2476
+ case ERROR_NO_UNICODE_TRANSLATION: { LogError("Cannot convert invalid UTF-16 string to UTF-8"); } break;
2496
2477
  default: { LogError("WideCharToMultiByte() failed: %1", GetWin32ErrorString()); } break;
2497
2478
  }
2498
2479
  return -1;
@@ -2512,16 +2493,16 @@ char *GetWin32ErrorString(uint32_t error_code)
2512
2493
  if (win32_utf8) {
2513
2494
  if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
2514
2495
  nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2515
- str_buf, RG_SIZE(str_buf), nullptr))
2496
+ str_buf, K_SIZE(str_buf), nullptr))
2516
2497
  goto fail;
2517
2498
  } else {
2518
2499
  wchar_t buf_w[256];
2519
2500
  if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
2520
2501
  nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2521
- buf_w, RG_SIZE(buf_w), nullptr))
2502
+ buf_w, K_SIZE(buf_w), nullptr))
2522
2503
  goto fail;
2523
2504
 
2524
- if (!WideCharToMultiByte(CP_UTF8, 0, buf_w, -1, str_buf, RG_SIZE(str_buf), nullptr, nullptr))
2505
+ if (!WideCharToMultiByte(CP_UTF8, 0, buf_w, -1, str_buf, K_SIZE(str_buf), nullptr, nullptr))
2525
2506
  goto fail;
2526
2507
  }
2527
2508
 
@@ -2611,7 +2592,7 @@ StatResult StatFile(int fd, const char *filename, unsigned int flags, FileInfo *
2611
2592
  } break;
2612
2593
  }
2613
2594
  }
2614
- RG_DEFER { CloseHandle(h); };
2595
+ K_DEFER { CloseHandle(h); };
2615
2596
 
2616
2597
  return StatHandle(h, filename, out_info);
2617
2598
  } else {
@@ -2622,7 +2603,7 @@ StatResult StatFile(int fd, const char *filename, unsigned int flags, FileInfo *
2622
2603
 
2623
2604
  RenameResult RenameFile(const char *src_filename, const char *dest_filename, unsigned int silent, unsigned int flags)
2624
2605
  {
2625
- RG_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
2606
+ K_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
2626
2607
 
2627
2608
  DWORD move_flags = (flags & (int)RenameFlag::Overwrite) ? MOVEFILE_REPLACE_EXISTING : 0;
2628
2609
  DWORD err = ERROR_SUCCESS;
@@ -2655,11 +2636,11 @@ RenameResult RenameFile(const char *src_filename, const char *dest_filename, uns
2655
2636
 
2656
2637
  if (err == ERROR_ALREADY_EXISTS) {
2657
2638
  if (!(silent & (int)RenameResult::AlreadyExists)) {
2658
- LogError("Failed to rename file '%1' to '%2': file already exists", src_filename, dest_filename);
2639
+ LogError("Failed to rename '%1' to '%2': file already exists", src_filename, dest_filename);
2659
2640
  }
2660
2641
  return RenameResult::AlreadyExists;
2661
2642
  } else {
2662
- LogError("Failed to rename file '%1' to '%2': %3", src_filename, dest_filename, GetWin32ErrorString(err));
2643
+ LogError("Failed to rename '%1' to '%2': %3", src_filename, dest_filename, GetWin32ErrorString(err));
2663
2644
  return RenameResult::OtherError;
2664
2645
  }
2665
2646
  }
@@ -2673,7 +2654,7 @@ bool ResizeFile(int fd, const char *filename, int64_t len)
2673
2654
  LogError("Failed to resize file '%1': %2", filename, GetWin32ErrorString());
2674
2655
  return false;
2675
2656
  }
2676
- RG_DEFER { SetFilePointerEx(h, prev_pos, nullptr, FILE_BEGIN); };
2657
+ K_DEFER { SetFilePointerEx(h, prev_pos, nullptr, FILE_BEGIN); };
2677
2658
 
2678
2659
  if (!SetFilePointerEx(h, { .QuadPart = len }, nullptr, FILE_BEGIN)) {
2679
2660
  LogError("Failed to resize file '%1': %2", filename, GetWin32ErrorString());
@@ -2744,7 +2725,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2744
2725
  FunctionRef<bool(const char *, const FileInfo &)> func)
2745
2726
  {
2746
2727
  if (filter) {
2747
- RG_ASSERT(!strpbrk(filter, RG_PATH_SEPARATORS));
2728
+ K_ASSERT(!strpbrk(filter, K_PATH_SEPARATORS));
2748
2729
  } else {
2749
2730
  filter = "*";
2750
2731
  }
@@ -2752,7 +2733,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2752
2733
  wchar_t find_filter_w[4096];
2753
2734
  {
2754
2735
  char find_filter[4096];
2755
- if (snprintf(find_filter, RG_SIZE(find_filter), "%s\\%s", dirname, filter) >= RG_SIZE(find_filter)) {
2736
+ if (snprintf(find_filter, K_SIZE(find_filter), "%s\\%s", dirname, filter) >= K_SIZE(find_filter)) {
2756
2737
  LogError("Cannot enumerate directory '%1': Path too long", dirname);
2757
2738
  return EnumResult::OtherError;
2758
2739
  }
@@ -2789,7 +2770,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2789
2770
  default: return EnumResult::OtherError;
2790
2771
  }
2791
2772
  }
2792
- RG_DEFER { FindClose(handle); };
2773
+ K_DEFER { FindClose(handle); };
2793
2774
 
2794
2775
  Size count = 0;
2795
2776
  do {
@@ -3009,19 +2990,19 @@ StatResult StatFile(int fd, const char *path, unsigned int flags, FileInfo *out_
3009
2990
  static bool SyncDirectory(Span<const char> directory)
3010
2991
  {
3011
2992
  char directory0[4096];
3012
- if (directory.len >= RG_SIZE(directory0)) {
2993
+ if (directory.len >= K_SIZE(directory0)) {
3013
2994
  LogError("Failed to sync directory '%1': path too long", directory);
3014
2995
  return false;
3015
2996
  }
3016
2997
  MemCpy(directory0, directory.ptr, directory.len);
3017
2998
  directory0[directory.len] = 0;
3018
2999
 
3019
- int dirfd = RG_RESTART_EINTR(open(directory0, O_RDONLY | O_CLOEXEC), < 0);
3000
+ int dirfd = K_RESTART_EINTR(open(directory0, O_RDONLY | O_CLOEXEC), < 0);
3020
3001
  if (dirfd < 0) {
3021
3002
  LogError("Failed to sync directory '%1': %2", directory, strerror(errno));
3022
3003
  return false;
3023
3004
  }
3024
- RG_DEFER { CloseDescriptor(dirfd); };
3005
+ K_DEFER { CloseDescriptor(dirfd); };
3025
3006
 
3026
3007
  if (fsync(dirfd) < 0) {
3027
3008
  LogError("Failed to sync directory '%1': %2", directory, strerror(errno));
@@ -3039,7 +3020,7 @@ static inline bool IsErrnoNotSupported(int err)
3039
3020
 
3040
3021
  RenameResult RenameFile(const char *src_filename, const char *dest_filename, unsigned int silent, unsigned int flags)
3041
3022
  {
3042
- RG_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
3023
+ K_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
3043
3024
 
3044
3025
  if (flags & (int)RenameFlag::Overwrite) {
3045
3026
  if (rename(src_filename, dest_filename) < 0)
@@ -3146,7 +3127,7 @@ bool SetFileMetaData(int fd, const char *filename, int64_t mtime, int64_t, uint3
3146
3127
  times[1].tv_nsec = (mtime % 1000) * 1000000;
3147
3128
 
3148
3129
  if (futimens(fd, times) < 0) {
3149
- LogError("Failed to set mtime of '%1'", filename);
3130
+ LogError("Failed to set modification time of '%1': %2", filename, filename);
3150
3131
  valid = false;
3151
3132
  }
3152
3133
  if (fchmod(fd, (mode_t)mode) < 0) {
@@ -3280,7 +3261,7 @@ static EnumResult ReadDirectory(DIR *dirp, const char *dirname, const char *filt
3280
3261
  EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_files,
3281
3262
  FunctionRef<bool(const char *, FileType)> func)
3282
3263
  {
3283
- DIR *dirp = RG_RESTART_EINTR(opendir(dirname), == nullptr);
3264
+ DIR *dirp = K_RESTART_EINTR(opendir(dirname), == nullptr);
3284
3265
  if (!dirp) {
3285
3266
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3286
3267
 
@@ -3290,7 +3271,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
3290
3271
  default: return EnumResult::OtherError;
3291
3272
  }
3292
3273
  }
3293
- RG_DEFER { closedir(dirp); };
3274
+ K_DEFER { closedir(dirp); };
3294
3275
 
3295
3276
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3296
3277
  }
@@ -3298,7 +3279,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
3298
3279
  EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_files,
3299
3280
  FunctionRef<bool(const char *, const FileInfo &)> func)
3300
3281
  {
3301
- DIR *dirp = RG_RESTART_EINTR(opendir(dirname), == nullptr);
3282
+ DIR *dirp = K_RESTART_EINTR(opendir(dirname), == nullptr);
3302
3283
  if (!dirp) {
3303
3284
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3304
3285
 
@@ -3308,7 +3289,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
3308
3289
  default: return EnumResult::OtherError;
3309
3290
  }
3310
3291
  }
3311
- RG_DEFER { closedir(dirp); };
3292
+ K_DEFER { closedir(dirp); };
3312
3293
 
3313
3294
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3314
3295
  }
@@ -3325,7 +3306,7 @@ EnumResult EnumerateDirectory(int fd, const char *dirname, const char *filter, S
3325
3306
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3326
3307
  return EnumResult::OtherError;
3327
3308
  }
3328
- RG_DEFER { closedir(dirp); };
3309
+ K_DEFER { closedir(dirp); };
3329
3310
 
3330
3311
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3331
3312
  }
@@ -3340,7 +3321,7 @@ EnumResult EnumerateDirectory(int fd, const char *dirname, const char *filter, S
3340
3321
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3341
3322
  return EnumResult::OtherError;
3342
3323
  }
3343
- RG_DEFER { closedir(dirp); };
3324
+ K_DEFER { closedir(dirp); };
3344
3325
 
3345
3326
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3346
3327
  }
@@ -3352,7 +3333,7 @@ EnumResult EnumerateDirectory(int fd, const char *dirname, const char *filter, S
3352
3333
  bool EnumerateFiles(const char *dirname, const char *filter, Size max_depth, Size max_files,
3353
3334
  Allocator *str_alloc, HeapArray<const char *> *out_files)
3354
3335
  {
3355
- RG_DEFER_NC(out_guard, len = out_files->len) { out_files->RemoveFrom(len); };
3336
+ K_DEFER_NC(out_guard, len = out_files->len) { out_files->RemoveFrom(len); };
3356
3337
 
3357
3338
  EnumResult ret = EnumerateDirectory(dirname, nullptr, max_files,
3358
3339
  [&](const char *basename, FileType file_type) {
@@ -3423,7 +3404,7 @@ bool TestFile(const char *filename, FileType type)
3423
3404
  case FileType::Pipe: { LogError("Path '%1' is not a pipe", filename); } break;
3424
3405
  case FileType::Socket: { LogError("Path '%1' is not a socket", filename); } break;
3425
3406
 
3426
- case FileType::Link: { RG_UNREACHABLE(); } break;
3407
+ case FileType::Link: { K_UNREACHABLE(); } break;
3427
3408
  }
3428
3409
 
3429
3410
  return false;
@@ -3561,7 +3542,7 @@ bool MatchPathSpec(const char *path, const char *spec, bool case_sensitive)
3561
3542
  Span<const char> path2 = path;
3562
3543
 
3563
3544
  do {
3564
- const char *it = SplitStrReverseAny(path2, RG_PATH_SEPARATORS, &path2).ptr;
3545
+ const char *it = SplitStrReverseAny(path2, K_PATH_SEPARATORS, &path2).ptr;
3565
3546
 
3566
3547
  if (MatchPathName(it, spec, case_sensitive))
3567
3548
  return true;
@@ -3572,10 +3553,10 @@ bool MatchPathSpec(const char *path, const char *spec, bool case_sensitive)
3572
3553
 
3573
3554
  bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *alloc, const char **out_path)
3574
3555
  {
3575
- RG_ASSERT(alloc || !out_path);
3556
+ K_ASSERT(alloc || !out_path);
3576
3557
 
3577
3558
  // Fast path
3578
- if (strpbrk(name, RG_PATH_SEPARATORS)) {
3559
+ if (strpbrk(name, K_PATH_SEPARATORS)) {
3579
3560
  if (!TestFile(name, FileType::File))
3580
3561
  return false;
3581
3562
 
@@ -3586,7 +3567,7 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
3586
3567
  }
3587
3568
 
3588
3569
  while (paths.len) {
3589
- Span<const char> path = SplitStr(paths, RG_PATH_DELIMITER, &paths);
3570
+ Span<const char> path = SplitStr(paths, K_PATH_DELIMITER, &paths);
3590
3571
 
3591
3572
  LocalArray<char, 4096> buf;
3592
3573
  buf.len = Fmt(buf.data, "%1%/%2", path, name).len;
@@ -3607,7 +3588,7 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
3607
3588
  }
3608
3589
  }
3609
3590
  #else
3610
- if (buf.len < RG_SIZE(buf.data) - 1 && TestFile(buf.data)) {
3591
+ if (buf.len < K_SIZE(buf.data) - 1 && TestFile(buf.data)) {
3611
3592
  if (out_path) {
3612
3593
  *out_path = DuplicateString(buf.data, alloc).ptr;
3613
3594
  }
@@ -3621,10 +3602,10 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
3621
3602
 
3622
3603
  bool FindExecutableInPath(const char *name, Allocator *alloc, const char **out_path)
3623
3604
  {
3624
- RG_ASSERT(alloc || !out_path);
3605
+ K_ASSERT(alloc || !out_path);
3625
3606
 
3626
3607
  // Fast path
3627
- if (strpbrk(name, RG_PATH_SEPARATORS)) {
3608
+ if (strpbrk(name, K_PATH_SEPARATORS)) {
3628
3609
  if (!TestFile(name, FileType::File))
3629
3610
  return false;
3630
3611
 
@@ -3640,13 +3621,13 @@ bool FindExecutableInPath(const char *name, Allocator *alloc, const char **out_p
3640
3621
  if (win32_utf8) {
3641
3622
  paths = GetEnv("PATH");
3642
3623
  } else {
3643
- wchar_t buf_w[RG_SIZE(env_buf.data)];
3644
- DWORD len = GetEnvironmentVariableW(L"PATH", buf_w, RG_LEN(buf_w));
3624
+ wchar_t buf_w[K_SIZE(env_buf.data)];
3625
+ DWORD len = GetEnvironmentVariableW(L"PATH", buf_w, K_LEN(buf_w));
3645
3626
 
3646
3627
  if (!len && GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
3647
3628
  LogError("Failed to get PATH environment variable: %1", GetWin32ErrorString());
3648
3629
  return false;
3649
- } else if (len >= RG_LEN(buf_w)) {
3630
+ } else if (len >= K_LEN(buf_w)) {
3650
3631
  LogError("Failed to get PATH environment variable: buffer to small");
3651
3632
  return false;
3652
3633
  }
@@ -3696,19 +3677,19 @@ const char *GetWorkingDirectory()
3696
3677
 
3697
3678
  #if defined(_WIN32)
3698
3679
  if (!win32_utf8) {
3699
- wchar_t buf_w[RG_SIZE(buf)];
3700
- DWORD ret = GetCurrentDirectoryW(RG_SIZE(buf_w), buf_w);
3701
- RG_ASSERT(ret && ret <= RG_SIZE(buf_w));
3680
+ wchar_t buf_w[K_SIZE(buf)];
3681
+ DWORD ret = GetCurrentDirectoryW(K_SIZE(buf_w), buf_w);
3682
+ K_ASSERT(ret && ret <= K_SIZE(buf_w));
3702
3683
 
3703
3684
  Size str_len = ConvertWin32WideToUtf8(buf_w, buf);
3704
- RG_ASSERT(str_len >= 0);
3685
+ K_ASSERT(str_len >= 0);
3705
3686
 
3706
3687
  return buf;
3707
3688
  }
3708
3689
  #endif
3709
3690
 
3710
- const char *ptr = getcwd(buf, RG_SIZE(buf));
3711
- RG_ASSERT(ptr);
3691
+ const char *ptr = getcwd(buf, K_SIZE(buf));
3692
+ K_ASSERT(ptr);
3712
3693
 
3713
3694
  return buf;
3714
3695
  }
@@ -3720,15 +3701,15 @@ const char *GetApplicationExecutable()
3720
3701
 
3721
3702
  if (!executable_path[0]) {
3722
3703
  if (win32_utf8) {
3723
- Size path_len = (Size)GetModuleFileNameA(nullptr, executable_path, RG_SIZE(executable_path));
3724
- RG_ASSERT(path_len && path_len < RG_SIZE(executable_path));
3704
+ Size path_len = (Size)GetModuleFileNameA(nullptr, executable_path, K_SIZE(executable_path));
3705
+ K_ASSERT(path_len && path_len < K_SIZE(executable_path));
3725
3706
  } else {
3726
- wchar_t path_w[RG_SIZE(executable_path)];
3727
- Size path_len = (Size)GetModuleFileNameW(nullptr, path_w, RG_SIZE(path_w));
3728
- RG_ASSERT(path_len && path_len < RG_LEN(path_w));
3707
+ wchar_t path_w[K_SIZE(executable_path)];
3708
+ Size path_len = (Size)GetModuleFileNameW(nullptr, path_w, K_SIZE(path_w));
3709
+ K_ASSERT(path_len && path_len < K_LEN(path_w));
3729
3710
 
3730
3711
  Size str_len = ConvertWin32WideToUtf8(path_w, executable_path);
3731
- RG_ASSERT(str_len >= 0);
3712
+ K_ASSERT(str_len >= 0);
3732
3713
  }
3733
3714
  }
3734
3715
 
@@ -3737,13 +3718,13 @@ const char *GetApplicationExecutable()
3737
3718
  static char executable_path[4096];
3738
3719
 
3739
3720
  if (!executable_path[0]) {
3740
- uint32_t buffer_size = RG_SIZE(executable_path);
3721
+ uint32_t buffer_size = K_SIZE(executable_path);
3741
3722
  int ret = _NSGetExecutablePath(executable_path, &buffer_size);
3742
- RG_ASSERT(!ret);
3723
+ K_ASSERT(!ret);
3743
3724
 
3744
3725
  char *path_buf = realpath(executable_path, nullptr);
3745
- RG_ASSERT(path_buf);
3746
- RG_ASSERT(strlen(path_buf) < RG_SIZE(executable_path));
3726
+ K_ASSERT(path_buf);
3727
+ K_ASSERT(strlen(path_buf) < K_SIZE(executable_path));
3747
3728
 
3748
3729
  CopyString(path_buf, executable_path);
3749
3730
  free(path_buf);
@@ -3754,8 +3735,8 @@ const char *GetApplicationExecutable()
3754
3735
  static char executable_path[4096];
3755
3736
 
3756
3737
  if (!executable_path[0]) {
3757
- ssize_t ret = readlink("/proc/self/exe", executable_path, RG_SIZE(executable_path));
3758
- RG_ASSERT(ret > 0 && ret < RG_SIZE(executable_path));
3738
+ ssize_t ret = readlink("/proc/self/exe", executable_path, K_SIZE(executable_path));
3739
+ K_ASSERT(ret > 0 && ret < K_SIZE(executable_path));
3759
3740
  }
3760
3741
 
3761
3742
  return executable_path;
@@ -3767,27 +3748,27 @@ const char *GetApplicationExecutable()
3767
3748
 
3768
3749
  size_t argc;
3769
3750
  {
3770
- int ret = sysctl(name, RG_LEN(name), nullptr, &argc, NULL, 0);
3771
- RG_ASSERT(ret >= 0);
3772
- RG_ASSERT(argc >= 1);
3751
+ int ret = sysctl(name, K_LEN(name), nullptr, &argc, NULL, 0);
3752
+ K_ASSERT(ret >= 0);
3753
+ K_ASSERT(argc >= 1);
3773
3754
  }
3774
3755
 
3775
3756
  HeapArray<char *> argv;
3776
3757
  {
3777
3758
  argv.AppendDefault(argc);
3778
- int ret = sysctl(name, RG_LEN(name), argv.ptr, &argc, nullptr, 0);
3779
- RG_ASSERT(ret >= 0);
3759
+ int ret = sysctl(name, K_LEN(name), argv.ptr, &argc, nullptr, 0);
3760
+ K_ASSERT(ret >= 0);
3780
3761
  }
3781
3762
 
3782
3763
  if (PathIsAbsolute(argv[0])) {
3783
- RG_ASSERT(strlen(argv[0]) < RG_SIZE(executable_path));
3764
+ K_ASSERT(strlen(argv[0]) < K_SIZE(executable_path));
3784
3765
 
3785
3766
  CopyString(argv[0], executable_path);
3786
3767
  } else {
3787
3768
  const char *path;
3788
3769
  bool success = FindExecutableInPath(argv[0], GetDefaultAllocator(), &path);
3789
- RG_ASSERT(success);
3790
- RG_ASSERT(strlen(path) < RG_SIZE(executable_path));
3770
+ K_ASSERT(success);
3771
+ K_ASSERT(strlen(path) < K_SIZE(executable_path));
3791
3772
 
3792
3773
  CopyString(path, executable_path);
3793
3774
  ReleaseRaw(nullptr, (void *)path, -1);
@@ -3802,9 +3783,9 @@ const char *GetApplicationExecutable()
3802
3783
  int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
3803
3784
  size_t len = sizeof(executable_path);
3804
3785
 
3805
- int ret = sysctl(name, RG_LEN(name), executable_path, &len, NULL, 0);
3806
- RG_ASSERT(ret >= 0);
3807
- RG_ASSERT(len < RG_SIZE(executable_path));
3786
+ int ret = sysctl(name, K_LEN(name), executable_path, &len, NULL, 0);
3787
+ K_ASSERT(ret >= 0);
3788
+ K_ASSERT(len < K_SIZE(executable_path));
3808
3789
  }
3809
3790
 
3810
3791
  return executable_path;
@@ -3833,7 +3814,7 @@ const char *GetApplicationDirectory()
3833
3814
  Span<const char> GetPathDirectory(Span<const char> filename)
3834
3815
  {
3835
3816
  Span<const char> directory;
3836
- SplitStrReverseAny(filename, RG_PATH_SEPARATORS, &directory);
3817
+ SplitStrReverseAny(filename, K_PATH_SEPARATORS, &directory);
3837
3818
 
3838
3819
  return directory.len ? directory : ".";
3839
3820
  }
@@ -3841,7 +3822,7 @@ Span<const char> GetPathDirectory(Span<const char> filename)
3841
3822
  // Names starting with a dot are not considered to be an extension (POSIX hidden files)
3842
3823
  Span<const char> GetPathExtension(Span<const char> filename, CompressionType *out_compression_type)
3843
3824
  {
3844
- filename = SplitStrReverseAny(filename, RG_PATH_SEPARATORS);
3825
+ filename = SplitStrReverseAny(filename, K_PATH_SEPARATORS);
3845
3826
 
3846
3827
  Span<const char> extension = {};
3847
3828
  const auto consume_next_extension = [&]() {
@@ -3880,7 +3861,7 @@ CompressionType GetPathCompression(Span<const char> filename)
3880
3861
 
3881
3862
  Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, unsigned int flags, Allocator *alloc)
3882
3863
  {
3883
- RG_ASSERT(alloc);
3864
+ K_ASSERT(alloc);
3884
3865
 
3885
3866
  if (!path.len && !root_directory.len)
3886
3867
  return Fmt(alloc, "");
@@ -3888,17 +3869,17 @@ Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory,
3888
3869
  HeapArray<char> buf(alloc);
3889
3870
  Size parts_count = 0;
3890
3871
 
3891
- char separator = (flags & (int)NormalizeFlag::ForceSlash) ? '/' : *RG_PATH_SEPARATORS;
3872
+ char separator = (flags & (int)NormalizeFlag::ForceSlash) ? '/' : *K_PATH_SEPARATORS;
3892
3873
 
3893
3874
  const auto append_normalized_path = [&](Span<const char> path) {
3894
3875
  if (!buf.len && PathIsAbsolute(path)) {
3895
- Span<const char> prefix = SplitStrAny(path, RG_PATH_SEPARATORS, &path);
3876
+ Span<const char> prefix = SplitStrAny(path, K_PATH_SEPARATORS, &path);
3896
3877
  buf.Append(prefix);
3897
3878
  buf.Append(separator);
3898
3879
  }
3899
3880
 
3900
3881
  while (path.len) {
3901
- Span<const char> part = SplitStrAny(path, RG_PATH_SEPARATORS, &path);
3882
+ Span<const char> part = SplitStrAny(path, K_PATH_SEPARATORS, &path);
3902
3883
 
3903
3884
  if (part == "..") {
3904
3885
  if (parts_count) {
@@ -3982,15 +3963,16 @@ bool PathContainsDotDot(const char *path)
3982
3963
 
3983
3964
  static bool CheckForDumbTerm()
3984
3965
  {
3985
- static bool init = false;
3986
- static bool dumb = false;
3987
-
3988
- if (!init) {
3966
+ static bool dumb = ([]() {
3989
3967
  const char *term = GetEnv("TERM");
3990
3968
 
3991
- dumb |= term && TestStr(term, "dumb");
3992
- dumb |= !!GetEnv("NO_COLOR");
3993
- }
3969
+ if (term && TestStr(term, "dumb"))
3970
+ return true;
3971
+ if (GetEnv("NO_COLOR"))
3972
+ return true;
3973
+
3974
+ return false;
3975
+ })();
3994
3976
 
3995
3977
  return dumb;
3996
3978
  }
@@ -3999,7 +3981,7 @@ static bool CheckForDumbTerm()
3999
3981
 
4000
3982
  OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silent, int *out_fd)
4001
3983
  {
4002
- RG_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
3984
+ K_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
4003
3985
 
4004
3986
  DWORD access = 0;
4005
3987
  DWORD share = 0;
@@ -4038,7 +4020,7 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4038
4020
  oflags = _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY | _O_NOINHERIT;
4039
4021
  } break;
4040
4022
  }
4041
- RG_ASSERT(oflags >= 0);
4023
+ K_ASSERT(oflags >= 0);
4042
4024
 
4043
4025
  if (flags & (int)OpenFlag::Keep) {
4044
4026
  if (creation == CREATE_ALWAYS) {
@@ -4047,20 +4029,20 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4047
4029
  oflags &= ~_O_TRUNC;
4048
4030
  }
4049
4031
  if (flags & (int)OpenFlag::Directory) {
4050
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4051
- RG_ASSERT(!(flags & (int)OpenFlag::Append));
4032
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4033
+ K_ASSERT(!(flags & (int)OpenFlag::Append));
4052
4034
 
4053
4035
  creation = OPEN_EXISTING;
4054
4036
  attributes = FILE_FLAG_BACKUP_SEMANTICS;
4055
4037
  oflags &= ~(_O_CREAT | _O_TRUNC | _O_BINARY);
4056
4038
  }
4057
4039
  if (flags & (int)OpenFlag::Exists) {
4058
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4040
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4059
4041
 
4060
4042
  creation = OPEN_EXISTING;
4061
4043
  oflags &= ~_O_CREAT;
4062
4044
  } else if (flags & (int)OpenFlag::Exclusive) {
4063
- RG_ASSERT(creation == CREATE_ALWAYS);
4045
+ K_ASSERT(creation == CREATE_ALWAYS);
4064
4046
 
4065
4047
  creation = CREATE_NEW;
4066
4048
  oflags |= (int)_O_EXCL;
@@ -4068,7 +4050,7 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4068
4050
 
4069
4051
  HANDLE h = nullptr;
4070
4052
  int fd = -1;
4071
- RG_DEFER_N(err_guard) {
4053
+ K_DEFER_N(err_guard) {
4072
4054
  CloseDescriptor(fd);
4073
4055
  if (h) {
4074
4056
  CloseHandle(h);
@@ -4129,7 +4111,7 @@ void CloseDescriptor(int fd)
4129
4111
 
4130
4112
  bool FlushFile(int fd, const char *filename)
4131
4113
  {
4132
- RG_ASSERT(filename);
4114
+ K_ASSERT(filename);
4133
4115
 
4134
4116
  HANDLE h = (HANDLE)_get_osfhandle(fd);
4135
4117
 
@@ -4177,7 +4159,7 @@ bool SpliceFile(int src_fd, const char *src_filename, int64_t src_offset,
4177
4159
  (RtlNtStatusToDosErrorFunc *)(void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlNtStatusToDosError");
4178
4160
 
4179
4161
  unsigned long err = RtlNtStatusToDosError(status);
4180
- LogError("Failed to copy '%1' to '%2': %2", GetWin32ErrorString(err));
4162
+ LogError("Failed to copy '%1' to '%2': %3", src_filename, dest_filename, GetWin32ErrorString(err));
4181
4163
 
4182
4164
  return false;
4183
4165
  }
@@ -4209,7 +4191,7 @@ bool SpliceFile(int src_fd, const char *src_filename, int64_t src_offset,
4209
4191
 
4210
4192
  while (size) {
4211
4193
  LocalArray<uint8_t, 655536> buf;
4212
- unsigned long count = (unsigned long)std::min(size, (int64_t)RG_SIZE(buf.data));
4194
+ unsigned long count = (unsigned long)std::min(size, (int64_t)K_SIZE(buf.data));
4213
4195
 
4214
4196
  buf.len = _read(src_fd, buf.data, count);
4215
4197
 
@@ -4251,7 +4233,7 @@ bool SpliceFile(int src_fd, const char *src_filename, int64_t src_offset,
4251
4233
  return true;
4252
4234
  }
4253
4235
 
4254
- RG_UNREACHABLE();
4236
+ K_UNREACHABLE();
4255
4237
  }
4256
4238
 
4257
4239
  bool FileIsVt100(int fd)
@@ -4291,11 +4273,6 @@ bool FileIsVt100(int fd)
4291
4273
  }
4292
4274
  }
4293
4275
 
4294
- if (emulation && win32_utf8) {
4295
- SetConsoleCP(CP_UTF8); // Does not work yet, but it might some day
4296
- SetConsoleOutputCP(CP_UTF8);
4297
- }
4298
-
4299
4276
  return emulation;
4300
4277
  }();
4301
4278
 
@@ -4441,7 +4418,7 @@ error:
4441
4418
 
4442
4419
  OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silent, int *out_fd)
4443
4420
  {
4444
- RG_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
4421
+ K_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
4445
4422
 
4446
4423
  int oflags = -1;
4447
4424
  switch (flags & ((int)OpenFlag::Read |
@@ -4452,29 +4429,29 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4452
4429
  case (int)OpenFlag::Read | (int)OpenFlag::Write: { oflags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC; } break;
4453
4430
  case (int)OpenFlag::Append: { oflags = O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC; } break;
4454
4431
  }
4455
- RG_ASSERT(oflags >= 0);
4432
+ K_ASSERT(oflags >= 0);
4456
4433
 
4457
4434
  if (flags & (int)OpenFlag::Keep) {
4458
4435
  oflags &= ~O_TRUNC;
4459
4436
  }
4460
4437
  if (flags & (int)OpenFlag::Directory) {
4461
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4462
- RG_ASSERT(!(flags & (int)OpenFlag::Append));
4438
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4439
+ K_ASSERT(!(flags & (int)OpenFlag::Append));
4463
4440
 
4464
4441
  oflags &= ~(O_CREAT | O_WRONLY | O_RDWR | O_TRUNC);
4465
4442
  }
4466
4443
  if (flags & (int)OpenFlag::Exists) {
4467
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4444
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4468
4445
  oflags &= ~O_CREAT;
4469
4446
  } else if (flags & (int)OpenFlag::Exclusive) {
4470
- RG_ASSERT(oflags & O_CREAT);
4447
+ K_ASSERT(oflags & O_CREAT);
4471
4448
  oflags |= O_EXCL;
4472
4449
  }
4473
4450
  if (flags & (int)OpenFlag::NoFollow) {
4474
4451
  oflags |= O_NOFOLLOW;
4475
4452
  }
4476
4453
 
4477
- int fd = RG_RESTART_EINTR(open(filename, oflags, 0644), < 0);
4454
+ int fd = K_RESTART_EINTR(open(filename, oflags, 0644), < 0);
4478
4455
  if (fd < 0) {
4479
4456
  OpenResult ret;
4480
4457
  switch (errno) {
@@ -4506,7 +4483,7 @@ void CloseDescriptor(int fd)
4506
4483
 
4507
4484
  bool FlushFile(int fd, const char *filename)
4508
4485
  {
4509
- RG_ASSERT(filename);
4486
+ K_ASSERT(filename);
4510
4487
 
4511
4488
  #if defined(__APPLE__)
4512
4489
  if (fsync(fd) < 0 && errno != EINVAL && errno != ENOTSUP) {
@@ -4639,7 +4616,7 @@ unsupported:
4639
4616
 
4640
4617
  while (size) {
4641
4618
  LocalArray<uint8_t, 655536> buf;
4642
- Size count = (Size)std::min(size, (int64_t)RG_SIZE(buf.data));
4619
+ Size count = (Size)std::min(size, (int64_t)K_SIZE(buf.data));
4643
4620
 
4644
4621
  buf.len = read(src_fd, buf.data, (size_t)count);
4645
4622
 
@@ -4681,7 +4658,7 @@ unsupported:
4681
4658
  return true;
4682
4659
  }
4683
4660
 
4684
- RG_UNREACHABLE();
4661
+ K_UNREACHABLE();
4685
4662
  }
4686
4663
 
4687
4664
  bool FileIsVt100(int fd)
@@ -4735,7 +4712,7 @@ bool MakeDirectory(const char *directory, bool error_if_exists)
4735
4712
  bool MakeDirectoryRec(Span<const char> directory)
4736
4713
  {
4737
4714
  char buf[4096];
4738
- if (directory.len >= RG_SIZE(buf)) [[unlikely]] {
4715
+ if (directory.len >= K_SIZE(buf)) [[unlikely]] {
4739
4716
  LogError("Path '%1' is too large", directory);
4740
4717
  return false;
4741
4718
  }
@@ -4761,7 +4738,7 @@ bool MakeDirectoryRec(Span<const char> directory)
4761
4738
  return false;
4762
4739
  }
4763
4740
 
4764
- buf[offset] = *RG_PATH_SEPARATORS;
4741
+ buf[offset] = *K_PATH_SEPARATORS;
4765
4742
  }
4766
4743
  }
4767
4744
 
@@ -4827,7 +4804,7 @@ bool CreateOverlappedPipe(bool overlap0, bool overlap1, PipeMode mode, HANDLE ou
4827
4804
  static LONG pipe_idx;
4828
4805
 
4829
4806
  HANDLE handles[2] = {};
4830
- RG_DEFER_N(handle_guard) {
4807
+ K_DEFER_N(handle_guard) {
4831
4808
  CloseHandleSafe(&handles[0]);
4832
4809
  CloseHandleSafe(&handles[1]);
4833
4810
  };
@@ -4939,14 +4916,14 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4939
4916
  LogError("Failed to create job object: %1", GetWin32ErrorString());
4940
4917
  return false;
4941
4918
  }
4942
- RG_DEFER { CloseHandleSafe(&job_handle); };
4919
+ K_DEFER { CloseHandleSafe(&job_handle); };
4943
4920
 
4944
4921
  // If I die, everyone dies!
4945
4922
  {
4946
4923
  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits = {};
4947
4924
  limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
4948
4925
 
4949
- if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &limits, RG_SIZE(limits))) {
4926
+ if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &limits, K_SIZE(limits))) {
4950
4927
  LogError("SetInformationJobObject() failed: %1", GetWin32ErrorString());
4951
4928
  return false;
4952
4929
  }
@@ -4954,7 +4931,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4954
4931
 
4955
4932
  // Create read pipes
4956
4933
  HANDLE in_pipe[2] = {};
4957
- RG_DEFER {
4934
+ K_DEFER {
4958
4935
  CloseHandleSafe(&in_pipe[0]);
4959
4936
  CloseHandleSafe(&in_pipe[1]);
4960
4937
  };
@@ -4963,7 +4940,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4963
4940
 
4964
4941
  // Create write pipes
4965
4942
  HANDLE out_pipe[2] = {};
4966
- RG_DEFER {
4943
+ K_DEFER {
4967
4944
  CloseHandleSafe(&out_pipe[0]);
4968
4945
  CloseHandleSafe(&out_pipe[1]);
4969
4946
  };
@@ -5012,7 +4989,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5012
4989
  // Start process
5013
4990
  HANDLE process_handle;
5014
4991
  {
5015
- RG_DEFER {
4992
+ K_DEFER {
5016
4993
  CloseHandleSafe(&si.hStdInput);
5017
4994
  CloseHandleSafe(&si.hStdOutput);
5018
4995
  CloseHandleSafe(&si.hStdError);
@@ -5052,7 +5029,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5052
5029
  CloseHandleSafe(&in_pipe[0]);
5053
5030
  CloseHandleSafe(&out_pipe[1]);
5054
5031
  }
5055
- RG_DEFER { CloseHandleSafe(&process_handle); };
5032
+ K_DEFER { CloseHandleSafe(&process_handle); };
5056
5033
 
5057
5034
  // Read and write standard process streams
5058
5035
  {
@@ -5074,11 +5051,11 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5074
5051
 
5075
5052
  if (!write_buf.len) {
5076
5053
  write_buf = in_func();
5077
- RG_ASSERT(write_buf.len >= 0);
5054
+ K_ASSERT(write_buf.len >= 0);
5078
5055
  }
5079
5056
 
5080
5057
  if (write_buf.len) {
5081
- RG_ASSERT(write_buf.len < UINT_MAX);
5058
+ K_ASSERT(write_buf.len < UINT_MAX);
5082
5059
 
5083
5060
  if (!WriteFileEx(in_pipe[1], write_buf.ptr, (DWORD)write_buf.len,
5084
5061
  &proc_in.ov, PendingIO::CompletionHandler)) {
@@ -5104,7 +5081,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5104
5081
  proc_out.len = -1;
5105
5082
  }
5106
5083
 
5107
- if (proc_out.len && !ReadFileEx(out_pipe[0], read_buf, RG_SIZE(read_buf), &proc_out.ov, PendingIO::CompletionHandler)) {
5084
+ if (proc_out.len && !ReadFileEx(out_pipe[0], read_buf, K_SIZE(read_buf), &proc_out.ov, PendingIO::CompletionHandler)) {
5108
5085
  proc_out.err = GetLastError();
5109
5086
  }
5110
5087
  }
@@ -5134,7 +5111,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5134
5111
  console_ctrl_event
5135
5112
  };
5136
5113
 
5137
- if (WaitForMultipleObjects(RG_LEN(events), events, FALSE, INFINITE) == WAIT_FAILED) {
5114
+ if (WaitForMultipleObjects(K_LEN(events), events, FALSE, INFINITE) == WAIT_FAILED) {
5138
5115
  LogError("WaitForMultipleObjects() failed: %1", GetWin32ErrorString());
5139
5116
  return false;
5140
5117
  }
@@ -5189,11 +5166,11 @@ static void DefaultSignalHandler(int signal)
5189
5166
  #endif
5190
5167
 
5191
5168
  pid_t pid = getpid();
5192
- RG_ASSERT(pid > 1);
5169
+ K_ASSERT(pid > 1);
5193
5170
 
5194
5171
  if (interrupt_pfd[1] >= 0) {
5195
5172
  char dummy = 0;
5196
- RG_IGNORE write(interrupt_pfd[1], &dummy, 1);
5173
+ K_IGNORE write(interrupt_pfd[1], &dummy, 1);
5197
5174
  }
5198
5175
 
5199
5176
  if (flag_signal) {
@@ -5249,7 +5226,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5249
5226
 
5250
5227
  // Create read pipes
5251
5228
  int in_pfd[2] = {-1, -1};
5252
- RG_DEFER {
5229
+ K_DEFER {
5253
5230
  CloseDescriptorSafe(&in_pfd[0]);
5254
5231
  CloseDescriptorSafe(&in_pfd[1]);
5255
5232
  };
@@ -5264,7 +5241,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5264
5241
 
5265
5242
  // Create write pipes
5266
5243
  int out_pfd[2] = {-1, -1};
5267
- RG_DEFER {
5244
+ K_DEFER {
5268
5245
  CloseDescriptorSafe(&out_pfd[0]);
5269
5246
  CloseDescriptorSafe(&out_pfd[1]);
5270
5247
  };
@@ -5325,7 +5302,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5325
5302
  LogError("Failed to set up standard process descriptors: %1", strerror(errno));
5326
5303
  return false;
5327
5304
  }
5328
- RG_DEFER { posix_spawn_file_actions_destroy(&file_actions); };
5305
+ K_DEFER { posix_spawn_file_actions_destroy(&file_actions); };
5329
5306
 
5330
5307
  if (in_func.IsValid() && (errno = posix_spawn_file_actions_adddup2(&file_actions, in_pfd[0], STDIN_FILENO))) {
5331
5308
  LogError("Failed to set up standard process descriptors: %1", strerror(errno));
@@ -5373,7 +5350,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5373
5350
  pfds.Append({ interrupt_pfd[0], POLLIN, 0 });
5374
5351
  }
5375
5352
 
5376
- if (RG_RESTART_EINTR(poll(pfds.data, (nfds_t)pfds.len, -1), < 0) < 0) {
5353
+ if (K_RESTART_EINTR(poll(pfds.data, (nfds_t)pfds.len, -1), < 0) < 0) {
5377
5354
  LogError("Failed to poll process I/O: %1", strerror(errno));
5378
5355
  break;
5379
5356
  }
@@ -5386,15 +5363,15 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5386
5363
  if (in_revents & (POLLHUP | POLLERR)) {
5387
5364
  CloseDescriptorSafe(&in_pfd[1]);
5388
5365
  } else if (in_revents & POLLOUT) {
5389
- RG_ASSERT(in_func.IsValid());
5366
+ K_ASSERT(in_func.IsValid());
5390
5367
 
5391
5368
  if (!write_buf.len) {
5392
5369
  write_buf = in_func();
5393
- RG_ASSERT(write_buf.len >= 0);
5370
+ K_ASSERT(write_buf.len >= 0);
5394
5371
  }
5395
5372
 
5396
5373
  if (write_buf.len) {
5397
- ssize_t write_len = RG_RESTART_EINTR(write(in_pfd[1], write_buf.ptr, (size_t)write_buf.len), < 0);
5374
+ ssize_t write_len = K_RESTART_EINTR(write(in_pfd[1], write_buf.ptr, (size_t)write_buf.len), < 0);
5398
5375
 
5399
5376
  if (write_len > 0) {
5400
5377
  write_buf.ptr += write_len;
@@ -5414,10 +5391,10 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5414
5391
  if (out_revents & POLLERR) {
5415
5392
  break;
5416
5393
  } else if (out_revents & (POLLIN | POLLHUP)) {
5417
- RG_ASSERT(out_func.IsValid());
5394
+ K_ASSERT(out_func.IsValid());
5418
5395
 
5419
5396
  uint8_t read_buf[4096];
5420
- ssize_t read_len = RG_RESTART_EINTR(read(out_pfd[0], read_buf, RG_SIZE(read_buf)), < 0);
5397
+ ssize_t read_len = K_RESTART_EINTR(read(out_pfd[0], read_buf, K_SIZE(read_buf)), < 0);
5421
5398
 
5422
5399
  if (read_len > 0) {
5423
5400
  out_func(MakeSpan(read_buf, read_len));
@@ -5448,7 +5425,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5448
5425
  int64_t start = GetMonotonicTime();
5449
5426
 
5450
5427
  for (;;) {
5451
- int ret = RG_RESTART_EINTR(waitpid(pid, &status, terminate ? WNOHANG : 0), < 0);
5428
+ int ret = K_RESTART_EINTR(waitpid(pid, &status, terminate ? WNOHANG : 0), < 0);
5452
5429
 
5453
5430
  if (ret < 0) {
5454
5431
  LogError("Failed to wait for process exit: %1", strerror(errno));
@@ -5486,18 +5463,18 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5486
5463
  HeapArray<uint8_t> *out_buf, int *out_code)
5487
5464
  {
5488
5465
  Size start_len = out_buf->len;
5489
- RG_DEFER_N(out_guard) { out_buf->RemoveFrom(start_len); };
5466
+ K_DEFER_N(out_guard) { out_buf->RemoveFrom(start_len); };
5490
5467
 
5491
5468
  // Check virtual memory limits
5492
5469
  {
5493
- Size memory_max = RG_SIZE_MAX - out_buf->len - 1;
5470
+ Size memory_max = K_SIZE_MAX - out_buf->len - 1;
5494
5471
 
5495
5472
  if (memory_max <= 0) [[unlikely]] {
5496
5473
  LogError("Exhausted memory limit");
5497
5474
  return false;
5498
5475
  }
5499
5476
 
5500
- RG_ASSERT(max_len);
5477
+ K_ASSERT(max_len);
5501
5478
  max_len = (max_len >= 0) ? std::min(max_len, memory_max) : memory_max;
5502
5479
  }
5503
5480
 
@@ -5578,8 +5555,8 @@ static HANDLE wait_msg_event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
5578
5555
 
5579
5556
  void WaitDelay(int64_t delay)
5580
5557
  {
5581
- RG_ASSERT(delay >= 0);
5582
- RG_ASSERT(delay < 1000ll * INT32_MAX);
5558
+ K_ASSERT(delay >= 0);
5559
+ K_ASSERT(delay < 1000ll * INT32_MAX);
5583
5560
 
5584
5561
  while (delay) {
5585
5562
  DWORD delay32 = (DWORD)std::min(delay, (int64_t)UINT32_MAX);
@@ -5589,15 +5566,31 @@ void WaitDelay(int64_t delay)
5589
5566
  }
5590
5567
  }
5591
5568
 
5592
- WaitForResult WaitForInterrupt(int64_t timeout)
5569
+ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready)
5593
5570
  {
5571
+ K_ASSERT(sources.len <= 62);
5572
+
5594
5573
  ignore_ctrl_event = InitConsoleCtrlHandler();
5595
- RG_ASSERT(ignore_ctrl_event);
5574
+ K_ASSERT(ignore_ctrl_event);
5596
5575
 
5597
- HANDLE events[] = {
5598
- console_ctrl_event,
5599
- wait_msg_event
5600
- };
5576
+ LocalArray<HANDLE, 64> events;
5577
+ DWORD wake = 0;
5578
+
5579
+ events.Append(console_ctrl_event);
5580
+ events.Append(wait_msg_event);
5581
+
5582
+ // There is no way to get a waitable HANDLE for the Win32 GUI message pump.
5583
+ // Instead, waitable sources (such as the system tray code) return NULL to indicate that
5584
+ // they need to wait for messages on the message pump.
5585
+ for (const WaitSource &src: sources) {
5586
+ if (src.handle) {
5587
+ events.Append(src.handle);
5588
+ } else {
5589
+ wake = QS_ALLINPUT;
5590
+ }
5591
+
5592
+ timeout = (int64_t)std::min((uint64_t)timeout, (uint64_t)src.timeout);
5593
+ }
5601
5594
 
5602
5595
  DWORD ret;
5603
5596
  if (timeout >= 0) {
@@ -5605,26 +5598,50 @@ WaitForResult WaitForInterrupt(int64_t timeout)
5605
5598
  DWORD timeout32 = (DWORD)std::min(timeout, (int64_t)UINT32_MAX);
5606
5599
  timeout -= timeout32;
5607
5600
 
5608
- ret = WaitForMultipleObjects(RG_LEN(events), events, FALSE, timeout32);
5601
+ ret = MsgWaitForMultipleObjects((DWORD)events.len, events.data, FALSE, timeout32, wake);
5609
5602
  } while (ret == WAIT_TIMEOUT && timeout);
5610
5603
  } else {
5611
- ret = WaitForMultipleObjects(RG_LEN(events), events, FALSE, INFINITE);
5604
+ ret = MsgWaitForMultipleObjects((DWORD)events.len, events.data, FALSE, INFINITE, wake);
5612
5605
  }
5613
5606
 
5614
5607
  switch (ret) {
5615
- case WAIT_OBJECT_0: return WaitForResult::Interrupt;
5608
+ case WAIT_OBJECT_0: return WaitResult::Interrupt;
5616
5609
  case WAIT_OBJECT_0 + 1: {
5617
5610
  ResetEvent(wait_msg_event);
5618
- return WaitForResult::Message;
5611
+ return WaitResult::Message;
5619
5612
  } break;
5620
5613
  default: {
5621
- RG_ASSERT(ret == WAIT_TIMEOUT);
5622
- return WaitForResult::Timeout;
5614
+ if (ret == WAIT_OBJECT_0 + events.len) {
5615
+ // Mark all sources with an interest in the message pump as ready
5616
+ if (out_ready) {
5617
+ uint64_t flags = 0;
5618
+ for (Size i = 0; i < sources.len; i++) {
5619
+ flags |= !sources[i].handle ? (1ull << i) : 0;
5620
+ }
5621
+ *out_ready = flags;
5622
+ }
5623
+ return WaitResult::Ready;
5624
+ }
5625
+
5626
+ Size idx = (Size)ret - WAIT_OBJECT_0 - 2;
5627
+ K_ASSERT(idx >= 0 && idx < sources.len);
5628
+
5629
+ if (out_ready) {
5630
+ *out_ready |= 1ull << idx;
5631
+ }
5632
+ return WaitResult::Ready;
5623
5633
  } break;
5634
+ case WAIT_TIMEOUT: return WaitResult::Timeout;
5624
5635
  }
5625
5636
  }
5626
5637
 
5627
- void SignalWaitFor()
5638
+ WaitResult WaitEvents(int64_t timeout)
5639
+ {
5640
+ Span<const WaitSource> sources = {};
5641
+ return WaitEvents(sources, timeout);
5642
+ }
5643
+
5644
+ void InterruptWait()
5628
5645
  {
5629
5646
  SetEvent(wait_msg_event);
5630
5647
  }
@@ -5633,8 +5650,8 @@ void SignalWaitFor()
5633
5650
 
5634
5651
  void WaitDelay(int64_t delay)
5635
5652
  {
5636
- RG_ASSERT(delay >= 0);
5637
- RG_ASSERT(delay < 1000ll * INT32_MAX);
5653
+ K_ASSERT(delay >= 0);
5654
+ K_ASSERT(delay < 1000ll * INT32_MAX);
5638
5655
 
5639
5656
  struct timespec ts;
5640
5657
  ts.tv_sec = (int)(delay / 1000);
@@ -5642,49 +5659,79 @@ void WaitDelay(int64_t delay)
5642
5659
 
5643
5660
  struct timespec rem;
5644
5661
  while (nanosleep(&ts, &rem) < 0) {
5645
- RG_ASSERT(errno == EINTR);
5662
+ K_ASSERT(errno == EINTR);
5646
5663
  ts = rem;
5647
5664
  }
5648
5665
  }
5649
5666
 
5650
5667
  #if !defined(__wasi__)
5651
5668
 
5652
- WaitForResult WaitForInterrupt(int64_t timeout)
5669
+ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready)
5653
5670
  {
5671
+ LocalArray<struct pollfd, 64> pfds;
5672
+ K_ASSERT(sources.len <= K_LEN(pfds.data));
5673
+
5654
5674
  static std::atomic_bool message { false };
5655
5675
 
5656
5676
  flag_signal = true;
5657
5677
  SetSignalHandler(SIGUSR1, [](int) { message = true; });
5658
5678
 
5659
- if (timeout >= 0) {
5660
- struct timespec ts;
5661
- ts.tv_sec = (int)(timeout / 1000);
5662
- ts.tv_nsec = (int)((timeout % 1000) * 1000000);
5679
+ for (const WaitSource &src: sources) {
5680
+ pfds.Append({ src.fd, (short)src.events, 0 });
5681
+ timeout = (int64_t)std::min((uint64_t)timeout, (uint64_t)src.timeout);
5682
+ }
5663
5683
 
5664
- struct timespec rem;
5665
- while (!explicit_signal && !message && nanosleep(&ts, &rem) < 0) {
5666
- RG_ASSERT(errno == EINTR);
5667
- ts = rem;
5684
+ int64_t start = (timeout >= 0) ? GetMonotonicTime() : 0;
5685
+ int64_t until = start + timeout;
5686
+ int timeout32 = (int)std::min(until - start, (int64_t)INT_MAX);
5687
+
5688
+ for (;;) {
5689
+ if (explicit_signal == SIGTERM) {
5690
+ return WaitResult::Exit;
5691
+ } else if (explicit_signal) {
5692
+ return WaitResult::Interrupt;
5693
+ } else if (message) {
5694
+ message = false;
5695
+ return WaitResult::Message;
5668
5696
  }
5669
- } else {
5670
- while (!explicit_signal && !message) {
5671
- pause();
5697
+
5698
+ int ready = poll(pfds.data, (nfds_t)pfds.len, timeout32);
5699
+
5700
+ if (ready < 0) {
5701
+ if (errno == EINTR)
5702
+ continue;
5703
+
5704
+ LogError("Failed to poll for events: %1", strerror(errno));
5705
+ return WaitResult::Error;
5706
+ } else if (ready > 0) {
5707
+ if (out_ready) {
5708
+ uint64_t flags = 0;
5709
+ for (Size i = 0; i < pfds.len; i++) {
5710
+ flags |= pfds[i].revents ? (1ull << i) : 0;
5711
+ }
5712
+ *out_ready = flags;
5713
+ }
5714
+ return WaitResult::Ready;
5672
5715
  }
5673
- }
5674
5716
 
5675
- if (explicit_signal == SIGTERM) {
5676
- return WaitForResult::Exit;
5677
- } else if (explicit_signal) {
5678
- return WaitForResult::Interrupt;
5679
- } else if (message) {
5680
- message = false;
5681
- return WaitForResult::Message;
5682
- } else {
5683
- return WaitForResult::Timeout;
5717
+ if (timeout >= 0) {
5718
+ int64_t now = GetMonotonicTime();
5719
+ if (now >= until)
5720
+ break;
5721
+ timeout32 = (int)std::min(until - now, (int64_t)INT_MAX);
5722
+ }
5684
5723
  }
5724
+
5725
+ return WaitResult::Timeout;
5726
+ }
5727
+
5728
+ WaitResult WaitEvents(int64_t timeout)
5729
+ {
5730
+ Span<const WaitSource> sources = {};
5731
+ return WaitEvents(sources, timeout);
5685
5732
  }
5686
5733
 
5687
- void SignalWaitFor()
5734
+ void InterruptWait()
5688
5735
  {
5689
5736
  pid_t pid = getpid();
5690
5737
  kill(pid, SIGUSR1);
@@ -5718,7 +5765,7 @@ int GetCoreCount()
5718
5765
  cores = (int)std::thread::hardware_concurrency();
5719
5766
  }
5720
5767
 
5721
- RG_ASSERT(cores > 0);
5768
+ K_ASSERT(cores > 0);
5722
5769
  }
5723
5770
 
5724
5771
  return cores;
@@ -5744,7 +5791,7 @@ bool RaiseMaximumOpenFiles(int limit)
5744
5791
  lim.rlim_cur = std::min(target, lim.rlim_max);
5745
5792
 
5746
5793
  if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
5747
- LogError("Could not raise RLIMIT_NOFILE: %2", strerror(errno));
5794
+ LogError("Could not raise RLIMIT_NOFILE: %1", strerror(errno));
5748
5795
  return false;
5749
5796
  }
5750
5797
 
@@ -5775,7 +5822,7 @@ bool DropRootIdentity()
5775
5822
  goto error;
5776
5823
  if (setreuid(uid, uid) < 0)
5777
5824
  goto error;
5778
- RG_CRITICAL(setuid(0) < 0, "Managed to regain root privileges");
5825
+ K_CRITICAL(setuid(0) < 0, "Managed to regain root privileges");
5779
5826
 
5780
5827
  return true;
5781
5828
 
@@ -5805,7 +5852,7 @@ bool NotifySystemd()
5805
5852
 
5806
5853
  addr.sun_family = AF_UNIX;
5807
5854
  addr.sun_path[0] = 0;
5808
- CopyString(addr_str, MakeSpan(addr.sun_path + 1, RG_SIZE(addr.sun_path) - 1));
5855
+ CopyString(addr_str, MakeSpan(addr.sun_path + 1, K_SIZE(addr.sun_path) - 1));
5809
5856
  } else if (addr_str[0] == '/') {
5810
5857
  if (strlen(addr_str) >= sizeof(addr.sun_path)) {
5811
5858
  LogError("Socket pathname in NOTIFY_SOCKET is too long");
@@ -5824,7 +5871,7 @@ bool NotifySystemd()
5824
5871
  LogError("Failed to create UNIX socket: %1", strerror(errno));
5825
5872
  return false;
5826
5873
  }
5827
- RG_DEFER { close(fd); };
5874
+ K_DEFER { close(fd); };
5828
5875
 
5829
5876
  struct iovec iov = {};
5830
5877
  struct msghdr msg = {};
@@ -5850,6 +5897,23 @@ bool NotifySystemd()
5850
5897
  // Main
5851
5898
  // ------------------------------------------------------------------------
5852
5899
 
5900
+ static InitHelper *init;
5901
+ static FinalizeHelper *finalize;
5902
+
5903
+ InitHelper::InitHelper(const char *name)
5904
+ : name(name)
5905
+ {
5906
+ next = init;
5907
+ init = this;
5908
+ }
5909
+
5910
+ FinalizeHelper::FinalizeHelper(const char *name)
5911
+ : name(name)
5912
+ {
5913
+ next = finalize;
5914
+ finalize = this;
5915
+ }
5916
+
5853
5917
  void InitApp()
5854
5918
  {
5855
5919
  #if defined(_WIN32)
@@ -5857,6 +5921,9 @@ void InitApp()
5857
5921
  _setmode(STDIN_FILENO, _O_BINARY);
5858
5922
  _setmode(STDOUT_FILENO, _O_BINARY);
5859
5923
  _setmode(STDERR_FILENO, _O_BINARY);
5924
+
5925
+ SetConsoleCP(CP_UTF8);
5926
+ SetConsoleOutputCP(CP_UTF8);
5860
5927
  #endif
5861
5928
 
5862
5929
  #if !defined(_WIN32) && !defined(__wasi__)
@@ -5873,12 +5940,16 @@ void InitApp()
5873
5940
  atexit([]() {
5874
5941
  if (interrupt_pfd[1] >= 0) {
5875
5942
  pid_t pid = getpid();
5876
- RG_ASSERT(pid > 1);
5943
+ K_ASSERT(pid > 1);
5877
5944
 
5878
5945
  SetSignalHandler(SIGTERM, [](int) {});
5879
5946
  kill(-pid, SIGTERM);
5880
5947
  }
5881
5948
  });
5949
+
5950
+ // Make sure timezone information is in place, which is useful if some kind of sandbox runs later and
5951
+ // the timezone information is not available (seccomp, namespace, landlock, whatever).
5952
+ tzset();
5882
5953
  #endif
5883
5954
 
5884
5955
  #if defined(__OpenBSD__)
@@ -5886,6 +5957,28 @@ void InitApp()
5886
5957
  // so we want to cache the result as soon as possible.
5887
5958
  GetApplicationExecutable();
5888
5959
  #endif
5960
+
5961
+ // Init libraries
5962
+ while (init) {
5963
+ #if defined(K_DEBUG)
5964
+ LogDebug("Init %1 library", init->name);
5965
+ #endif
5966
+
5967
+ init->Run();
5968
+ init = init->next;
5969
+ }
5970
+ }
5971
+
5972
+ void ExitApp()
5973
+ {
5974
+ while (finalize) {
5975
+ #if defined(K_DEBUG)
5976
+ LogDebug("Finalize %1 library", finalize->name);
5977
+ #endif
5978
+
5979
+ finalize->Run();
5980
+ finalize = finalize->next;
5981
+ }
5889
5982
  }
5890
5983
 
5891
5984
  // ------------------------------------------------------------------------
@@ -5896,18 +5989,18 @@ void InitApp()
5896
5989
 
5897
5990
  const char *GetUserConfigPath(const char *name, Allocator *alloc)
5898
5991
  {
5899
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
5992
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5900
5993
 
5901
5994
  static char cache_dir[4096];
5902
5995
  static std::once_flag flag;
5903
5996
 
5904
5997
  std::call_once(flag, []() {
5905
5998
  wchar_t *dir = nullptr;
5906
- RG_DEFER { CoTaskMemFree(dir); };
5999
+ K_DEFER { CoTaskMemFree(dir); };
5907
6000
 
5908
- RG_CRITICAL(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &dir) == S_OK,
6001
+ K_CRITICAL(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &dir) == S_OK,
5909
6002
  "Failed to retrieve path to roaming user AppData");
5910
- RG_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
6003
+ K_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
5911
6004
  "Path to roaming AppData is invalid or too big");
5912
6005
  });
5913
6006
 
@@ -5917,18 +6010,18 @@ const char *GetUserConfigPath(const char *name, Allocator *alloc)
5917
6010
 
5918
6011
  const char *GetUserCachePath(const char *name, Allocator *alloc)
5919
6012
  {
5920
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6013
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5921
6014
 
5922
6015
  static char cache_dir[4096];
5923
6016
  static std::once_flag flag;
5924
6017
 
5925
6018
  std::call_once(flag, []() {
5926
6019
  wchar_t *dir = nullptr;
5927
- RG_DEFER { CoTaskMemFree(dir); };
6020
+ K_DEFER { CoTaskMemFree(dir); };
5928
6021
 
5929
- RG_CRITICAL(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &dir) == S_OK,
6022
+ K_CRITICAL(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &dir) == S_OK,
5930
6023
  "Failed to retrieve path to local user AppData");
5931
- RG_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
6024
+ K_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
5932
6025
  "Path to local AppData is invalid or too big");
5933
6026
  });
5934
6027
 
@@ -5944,16 +6037,16 @@ const char *GetTemporaryDirectory()
5944
6037
  std::call_once(flag, []() {
5945
6038
  Size len;
5946
6039
  if (win32_utf8) {
5947
- len = (Size)GetTempPathA(RG_SIZE(temp_dir), temp_dir);
5948
- RG_CRITICAL(len < RG_SIZE(temp_dir), "Temporary directory path is too big");
6040
+ len = (Size)GetTempPathA(K_SIZE(temp_dir), temp_dir);
6041
+ K_CRITICAL(len < K_SIZE(temp_dir), "Temporary directory path is too big");
5949
6042
  } else {
5950
6043
  static wchar_t dir_w[4096];
5951
- Size len_w = (Size)GetTempPathW(RG_LEN(dir_w), dir_w);
6044
+ Size len_w = (Size)GetTempPathW(K_LEN(dir_w), dir_w);
5952
6045
 
5953
- RG_CRITICAL(len_w < RG_LEN(dir_w), "Temporary directory path is too big");
6046
+ K_CRITICAL(len_w < K_LEN(dir_w), "Temporary directory path is too big");
5954
6047
 
5955
6048
  len = ConvertWin32WideToUtf8(dir_w, temp_dir);
5956
- RG_CRITICAL(len >= 0, "Temporary directory path is invalid or too big");
6049
+ K_CRITICAL(len >= 0, "Temporary directory path is invalid or too big");
5957
6050
  }
5958
6051
 
5959
6052
  while (len > 0 && IsPathSeparator(temp_dir[len - 1])) {
@@ -5969,7 +6062,7 @@ const char *GetTemporaryDirectory()
5969
6062
 
5970
6063
  const char *GetUserConfigPath(const char *name, Allocator *alloc)
5971
6064
  {
5972
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6065
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5973
6066
 
5974
6067
  const char *xdg = GetEnv("XDG_CONFIG_HOME");
5975
6068
  const char *home = GetEnv("HOME");
@@ -5994,7 +6087,7 @@ const char *GetUserConfigPath(const char *name, Allocator *alloc)
5994
6087
 
5995
6088
  const char *GetUserCachePath(const char *name, Allocator *alloc)
5996
6089
  {
5997
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6090
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5998
6091
 
5999
6092
  const char *xdg = GetEnv("XDG_CACHE_HOME");
6000
6093
  const char *home = GetEnv("HOME");
@@ -6019,7 +6112,7 @@ const char *GetUserCachePath(const char *name, Allocator *alloc)
6019
6112
 
6020
6113
  const char *GetSystemConfigPath(const char *name, Allocator *alloc)
6021
6114
  {
6022
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6115
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
6023
6116
 
6024
6117
  const char *path = Fmt(alloc, "/etc/%1", name).ptr;
6025
6118
  return path;
@@ -6037,7 +6130,7 @@ const char *GetTemporaryDirectory()
6037
6130
  env.len--;
6038
6131
  }
6039
6132
 
6040
- if (env.len && env.len < RG_SIZE(temp_dir)) {
6133
+ if (env.len && env.len < K_SIZE(temp_dir)) {
6041
6134
  CopyString(env, temp_dir);
6042
6135
  } else {
6043
6136
  CopyString("/tmp", temp_dir);
@@ -6052,7 +6145,7 @@ const char *GetTemporaryDirectory()
6052
6145
  const char *FindConfigFile(const char *directory, Span<const char *const> names,
6053
6146
  Allocator *alloc, HeapArray<const char *> *out_possibilities)
6054
6147
  {
6055
- RG_ASSERT(!directory || directory[0]);
6148
+ K_ASSERT(!directory || directory[0]);
6056
6149
 
6057
6150
  decltype(GetUserConfigPath) *funcs[] = {
6058
6151
  GetUserConfigPath,
@@ -6078,7 +6171,7 @@ const char *FindConfigFile(const char *directory, Span<const char *const> names,
6078
6171
 
6079
6172
  LocalArray<const char *, 8> tests;
6080
6173
  {
6081
- RG_ASSERT(names.len <= tests.Available());
6174
+ K_ASSERT(names.len <= tests.Available());
6082
6175
 
6083
6176
  for (const char *name: names) {
6084
6177
  if (directory) {
@@ -6113,11 +6206,11 @@ const char *FindConfigFile(const char *directory, Span<const char *const> names,
6113
6206
  static const char *CreateUniquePath(Span<const char> directory, const char *prefix, const char *extension,
6114
6207
  Allocator *alloc, FunctionRef<bool(const char *path)> create)
6115
6208
  {
6116
- RG_ASSERT(alloc);
6209
+ K_ASSERT(alloc);
6117
6210
 
6118
6211
  HeapArray<char> filename(alloc);
6119
6212
  filename.Append(directory);
6120
- filename.Append(*RG_PATH_SEPARATORS);
6213
+ filename.Append(*K_PATH_SEPARATORS);
6121
6214
  if (prefix) {
6122
6215
  filename.Append(prefix);
6123
6216
  filename.Append('.');
@@ -6126,7 +6219,7 @@ static const char *CreateUniquePath(Span<const char> directory, const char *pref
6126
6219
  Size change_offset = filename.len;
6127
6220
 
6128
6221
  PushLogFilter([](LogLevel, const char *, const char *, FunctionRef<LogFunc>) {});
6129
- RG_DEFER_N(log_guard) { PopLogFilter(); };
6222
+ K_DEFER_N(log_guard) { PopLogFilter(); };
6130
6223
 
6131
6224
  for (Size i = 0; i < 1000; i++) {
6132
6225
  // We want to show an error on last try
@@ -6191,9 +6284,9 @@ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags, Span<c
6191
6284
  bool value = false;
6192
6285
 
6193
6286
  switch (str.len) {
6194
- default: { RG_ASSERT(str.len >= 0); } [[fallthrough]];
6287
+ default: { K_ASSERT(str.len >= 0); } [[fallthrough]];
6195
6288
 
6196
- #if defined(RG_BIG_ENDIAN)
6289
+ #if defined(K_BIG_ENDIAN)
6197
6290
  case 8: { u.raw[0] = LowerAscii(str[7]); } [[fallthrough]];
6198
6291
  case 7: { u.raw[1] = LowerAscii(str[6]); } [[fallthrough]];
6199
6292
  case 6: { u.raw[2] = LowerAscii(str[5]); } [[fallthrough]];
@@ -6446,7 +6539,7 @@ malformed:
6446
6539
  bool ParseVersion(Span<const char> str, int parts, int multiplier,
6447
6540
  int64_t *out_version, unsigned int flags, Span<const char> *out_remaining)
6448
6541
  {
6449
- RG_ASSERT(parts >= 0 && parts < 6);
6542
+ K_ASSERT(parts >= 0 && parts < 6);
6450
6543
 
6451
6544
  int64_t version = 0;
6452
6545
  Span<const char> remain = str;
@@ -6513,35 +6606,42 @@ static inline uint64_t ROTL64(uint64_t v, int n)
6513
6606
  return (v << n) | (v >> (64 - n));
6514
6607
  }
6515
6608
 
6516
- static void InitChaCha20(uint32_t state[16], uint32_t key[8], uint32_t iv[2])
6609
+ static inline uint32_t LE32(const uint8_t *ptr)
6517
6610
  {
6518
- alignas(uint32_t) static char str[] = "expand 32-byte k";
6519
- const uint32_t *magic = (const uint32_t *)str;
6611
+ return ((uint32_t)ptr[0] << 0) |
6612
+ ((uint32_t)ptr[1] << 8) |
6613
+ ((uint32_t)ptr[2] << 16) |
6614
+ ((uint32_t)ptr[3] << 24);
6615
+ }
6616
+
6617
+ void InitChaCha20(uint32_t state[16], const uint8_t key[32], const uint8_t iv[8], const uint8_t counter[8])
6618
+ {
6619
+ static uint8_t magic[] = "expand 32-byte k";
6520
6620
 
6521
- state[0] = LittleEndian(magic[0]);
6522
- state[1] = LittleEndian(magic[1]);
6523
- state[2] = LittleEndian(magic[2]);
6524
- state[3] = LittleEndian(magic[3]);
6525
- state[4] = LittleEndian(key[0]);
6526
- state[5] = LittleEndian(key[1]);
6527
- state[6] = LittleEndian(key[2]);
6528
- state[7] = LittleEndian(key[3]);
6529
- state[8] = LittleEndian(key[4]);
6530
- state[9] = LittleEndian(key[5]);
6531
- state[10] = LittleEndian(key[6]);
6532
- state[11] = LittleEndian(key[7]);
6533
- state[12] = 0;
6534
- state[13] = 0;
6535
- state[14] = LittleEndian(iv[0]);
6536
- state[15] = LittleEndian(iv[1]);
6621
+ state[0] = LE32(magic + 0);
6622
+ state[1] = LE32(magic + 4);
6623
+ state[2] = LE32(magic + 8);
6624
+ state[3] = LE32(magic + 12);
6625
+ state[4] = LE32(key + 0);
6626
+ state[5] = LE32(key + 4);
6627
+ state[6] = LE32(key + 8);
6628
+ state[7] = LE32(key + 12);
6629
+ state[8] = LE32(key + 16);
6630
+ state[9] = LE32(key + 20);
6631
+ state[10] = LE32(key + 24);
6632
+ state[11] = LE32(key + 28);
6633
+ state[12] = counter ? LE32(counter + 0) : 0;
6634
+ state[13] = counter ? LE32(counter + 4) : 0;
6635
+ state[14] = LE32(iv + 0);
6636
+ state[15] = LE32(iv + 4);
6537
6637
  }
6538
6638
 
6539
- static void RunChaCha20(uint32_t state[16], uint8_t out_buf[64])
6639
+ void RunChaCha20(uint32_t state[16], uint8_t out_buf[64])
6540
6640
  {
6541
6641
  uint32_t *out_buf32 = (uint32_t *)out_buf;
6542
6642
 
6543
6643
  uint32_t x[16];
6544
- MemCpy(x, state, RG_SIZE(x));
6644
+ MemCpy(x, state, K_SIZE(x));
6545
6645
 
6546
6646
  for (Size i = 0; i < 20; i += 2) {
6547
6647
  x[0] += x[4]; x[12] = ROTL32(x[12] ^ x[0], 16);
@@ -6585,7 +6685,7 @@ static void RunChaCha20(uint32_t state[16], uint8_t out_buf[64])
6585
6685
  x[9] += x[14]; x[4] = ROTL32(x[4] ^ x[9], 7);
6586
6686
  }
6587
6687
 
6588
- for (Size i = 0; i < RG_LEN(x); i++) {
6688
+ for (Size i = 0; i < K_LEN(x); i++) {
6589
6689
  out_buf32[i] = LittleEndian(x[i] + state[i]);
6590
6690
  }
6591
6691
 
@@ -6605,26 +6705,26 @@ void FillRandomSafe(void *out_buf, Size len)
6605
6705
  #endif
6606
6706
 
6607
6707
  if (reseed) {
6608
- struct { uint32_t key[8]; uint32_t iv[2]; } buf;
6708
+ struct { uint8_t key[32]; uint8_t iv[8]; } buf;
6609
6709
 
6610
- MemSet(rnd_state, 0, RG_SIZE(rnd_state));
6710
+ MemSet(rnd_state, 0, K_SIZE(rnd_state));
6611
6711
  #if defined(_WIN32)
6612
- RG_CRITICAL(RtlGenRandom(&buf, RG_SIZE(buf)), "RtlGenRandom() failed: %1", GetWin32ErrorString());
6712
+ K_CRITICAL(RtlGenRandom(&buf, K_SIZE(buf)), "RtlGenRandom() failed: %1", GetWin32ErrorString());
6613
6713
  #elif defined(__linux__)
6614
6714
  {
6615
6715
  restart:
6616
- int ret = syscall(SYS_getrandom, &buf, RG_SIZE(buf), 0);
6617
- RG_CRITICAL(ret >= 0, "getrandom() failed: %1", strerror(errno));
6716
+ int ret = syscall(SYS_getrandom, &buf, K_SIZE(buf), 0);
6717
+ K_CRITICAL(ret >= 0, "getrandom() failed: %1", strerror(errno));
6618
6718
 
6619
- if (ret < RG_SIZE(buf)) [[unlikely]]
6719
+ if (ret < K_SIZE(buf)) [[unlikely]]
6620
6720
  goto restart;
6621
6721
  }
6622
6722
  #else
6623
- RG_CRITICAL(getentropy(&buf, RG_SIZE(buf)) == 0, "getentropy() failed: %1", strerror(errno));
6723
+ K_CRITICAL(getentropy(&buf, K_SIZE(buf)) == 0, "getentropy() failed: %1", strerror(errno));
6624
6724
  #endif
6625
6725
 
6626
6726
  InitChaCha20(rnd_state, buf.key, buf.iv);
6627
- ZeroSafe(&buf, RG_SIZE(buf));
6727
+ ZeroSafe(&buf, K_SIZE(buf));
6628
6728
 
6629
6729
  rnd_remain = Mebibytes(4);
6630
6730
  rnd_time = GetMonotonicTime();
@@ -6632,18 +6732,18 @@ restart:
6632
6732
  rnd_pid = getpid();
6633
6733
  #endif
6634
6734
 
6635
- rnd_offset = RG_SIZE(rnd_buf);
6735
+ rnd_offset = K_SIZE(rnd_buf);
6636
6736
  }
6637
6737
 
6638
- Size copy_len = std::min(RG_SIZE(rnd_buf) - rnd_offset, len);
6738
+ Size copy_len = std::min(K_SIZE(rnd_buf) - rnd_offset, len);
6639
6739
  MemCpy(out_buf, rnd_buf + rnd_offset, copy_len);
6640
6740
  ZeroSafe(rnd_buf + rnd_offset, copy_len);
6641
6741
  rnd_offset += copy_len;
6642
6742
 
6643
- for (Size i = copy_len; i < len; i += RG_SIZE(rnd_buf)) {
6743
+ for (Size i = copy_len; i < len; i += K_SIZE(rnd_buf)) {
6644
6744
  RunChaCha20(rnd_state, rnd_buf);
6645
6745
 
6646
- copy_len = std::min(RG_SIZE(rnd_buf), len - i);
6746
+ copy_len = std::min(K_SIZE(rnd_buf), len - i);
6647
6747
  MemCpy((uint8_t *)out_buf + i, rnd_buf, copy_len);
6648
6748
  ZeroSafe(rnd_buf, copy_len);
6649
6749
  rnd_offset = copy_len;
@@ -6655,7 +6755,7 @@ restart:
6655
6755
  FastRandom::FastRandom()
6656
6756
  {
6657
6757
  do {
6658
- FillRandomSafe(state, RG_SIZE(state));
6758
+ FillRandomSafe(state, K_SIZE(state));
6659
6759
  } while (std::all_of(std::begin(state), std::end(state), [](uint64_t v) { return !v; }));
6660
6760
  }
6661
6761
 
@@ -6672,12 +6772,30 @@ FastRandom::FastRandom(uint64_t seed)
6672
6772
  }
6673
6773
  }
6674
6774
 
6775
+ uint64_t FastRandom::Next()
6776
+ {
6777
+ // xoshiro256++ by David Blackman and Sebastiano Vigna (vigna@acm.org)
6778
+ // Hopefully I did not screw it up :)
6779
+
6780
+ uint64_t result = ROTL64(state[0] + state[3], 23) + state[0];
6781
+ uint64_t t = state[1] << 17;
6782
+
6783
+ state[2] ^= state[0];
6784
+ state[3] ^= state[1];
6785
+ state[1] ^= state[2];
6786
+ state[0] ^= state[3];
6787
+ state[2] ^= t;
6788
+ state[3] = ROTL64(state[3], 45);
6789
+
6790
+ return result;
6791
+ }
6792
+
6675
6793
  void FastRandom::Fill(void *out_buf, Size len)
6676
6794
  {
6677
6795
  for (Size i = 0; i < len; i += 8) {
6678
6796
  uint64_t rnd = Next();
6679
6797
 
6680
- Size copy_len = std::min(RG_SIZE(rnd), len - i);
6798
+ Size copy_len = std::min(K_SIZE(rnd), len - i);
6681
6799
  MemCpy((uint8_t *)out_buf + i, &rnd, copy_len);
6682
6800
  }
6683
6801
  }
@@ -6687,7 +6805,7 @@ int FastRandom::GetInt(int min, int max)
6687
6805
  int range = max - min;
6688
6806
 
6689
6807
  if (range < 2) [[unlikely]] {
6690
- RG_ASSERT(range >= 1);
6808
+ K_ASSERT(range >= 1);
6691
6809
  return min;
6692
6810
  }
6693
6811
 
@@ -6707,7 +6825,7 @@ int64_t FastRandom::GetInt64(int64_t min, int64_t max)
6707
6825
  int64_t range = max - min;
6708
6826
 
6709
6827
  if (range < 2) [[unlikely]] {
6710
- RG_ASSERT(range >= 1);
6828
+ K_ASSERT(range >= 1);
6711
6829
  return min;
6712
6830
  }
6713
6831
 
@@ -6722,22 +6840,9 @@ int64_t FastRandom::GetInt64(int64_t min, int64_t max)
6722
6840
  return min + (int64_t)x;
6723
6841
  }
6724
6842
 
6725
- uint64_t FastRandom::Next()
6843
+ uint64_t GetRandom()
6726
6844
  {
6727
- // xoshiro256++ by David Blackman and Sebastiano Vigna (vigna@acm.org)
6728
- // Hopefully I did not screw it up :)
6729
-
6730
- uint64_t result = ROTL64(state[0] + state[3], 23) + state[0];
6731
- uint64_t t = state[1] << 17;
6732
-
6733
- state[2] ^= state[0];
6734
- state[3] ^= state[1];
6735
- state[1] ^= state[2];
6736
- state[0] ^= state[3];
6737
- state[2] ^= t;
6738
- state[3] = ROTL64(state[3], 45);
6739
-
6740
- return result;
6845
+ return rng_fast.Next();
6741
6846
  }
6742
6847
 
6743
6848
  int GetRandomInt(int min, int max)
@@ -6774,7 +6879,7 @@ bool InitWinsock()
6774
6879
  return;
6775
6880
  }
6776
6881
 
6777
- RG_ASSERT(LOBYTE(wsa.wVersion) == 2 && HIBYTE(wsa.wVersion) == 2);
6882
+ K_ASSERT(LOBYTE(wsa.wVersion) == 2 && HIBYTE(wsa.wVersion) == 2);
6778
6883
  atexit([]() { WSACleanup(); });
6779
6884
 
6780
6885
  ready = true;
@@ -6805,7 +6910,7 @@ int CreateSocket(SocketType type, int flags)
6805
6910
  LogError("Failed to create IP socket: %1", GetWin32ErrorString());
6806
6911
  return -1;
6807
6912
  }
6808
- RG_DEFER_N(err_guard) { closesocket(sock); };
6913
+ K_DEFER_N(err_guard) { closesocket(sock); };
6809
6914
 
6810
6915
  int reuse = 1;
6811
6916
  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
@@ -6842,10 +6947,10 @@ int CreateSocket(SocketType type, int flags)
6842
6947
 
6843
6948
  int sock = socket(family, flags, 0);
6844
6949
  if (sock < 0) {
6845
- LogError("Failed to create AF_INET socket: %1", strerror(errno));
6950
+ LogError("Failed to create IP socket: %1", strerror(errno));
6846
6951
  return -1;
6847
6952
  }
6848
- RG_DEFER_N(err_guard) { close(sock); };
6953
+ K_DEFER_N(err_guard) { close(sock); };
6849
6954
 
6850
6955
  #if !defined(SOCK_CLOEXEC)
6851
6956
  fcntl(sock, F_SETFD, FD_CLOEXEC);
@@ -6878,7 +6983,7 @@ int CreateSocket(SocketType type, int flags)
6878
6983
 
6879
6984
  bool BindIPSocket(int sock, SocketType type, int port)
6880
6985
  {
6881
- RG_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
6986
+ K_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
6882
6987
 
6883
6988
  if (type == SocketType::IPv4) {
6884
6989
  struct sockaddr_in addr = {};
@@ -6944,12 +7049,12 @@ bool BindUnixSocket(int sock, const char *path)
6944
7049
 
6945
7050
  int OpenIPSocket(SocketType type, int port, int flags)
6946
7051
  {
6947
- RG_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
7052
+ K_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
6948
7053
 
6949
7054
  int sock = CreateSocket(type, flags);
6950
7055
  if (sock < 0)
6951
7056
  return -1;
6952
- RG_DEFER_N(err_guard) { CloseSocket(sock); };
7057
+ K_DEFER_N(err_guard) { CloseSocket(sock); };
6953
7058
 
6954
7059
  if (!BindIPSocket(sock, type, port))
6955
7060
  return -1;
@@ -6963,7 +7068,7 @@ int OpenUnixSocket(const char *path, int flags)
6963
7068
  int sock = CreateSocket(SocketType::Unix, flags);
6964
7069
  if (sock < 0)
6965
7070
  return -1;
6966
- RG_DEFER_N(err_guard) { CloseSocket(sock); };
7071
+ K_DEFER_N(err_guard) { CloseSocket(sock); };
6967
7072
 
6968
7073
  if (!BindUnixSocket(sock, path))
6969
7074
  return -1;
@@ -6985,7 +7090,7 @@ int ConnectToUnixSocket(const char *path, int flags)
6985
7090
  int sock = CreateSocket(SocketType::Unix, flags);
6986
7091
  if (sock < 0)
6987
7092
  return -1;
6988
- RG_DEFER_N(err_guard) { CloseSocket(sock); };
7093
+ K_DEFER_N(err_guard) { CloseSocket(sock); };
6989
7094
 
6990
7095
  if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
6991
7096
  #if defined(_WIN32)
@@ -7071,7 +7176,7 @@ struct WorkerData {
7071
7176
  };
7072
7177
 
7073
7178
  class AsyncPool {
7074
- RG_DELETE_COPY(AsyncPool)
7179
+ K_DELETE_COPY(AsyncPool)
7075
7180
 
7076
7181
  std::mutex pool_mutex;
7077
7182
  std::condition_variable pending_cv;
@@ -7113,7 +7218,7 @@ static thread_local bool async_running_task = false;
7113
7218
 
7114
7219
  Async::Async(int threads)
7115
7220
  {
7116
- RG_ASSERT(threads);
7221
+ K_ASSERT(threads);
7117
7222
 
7118
7223
  if (threads > 0) {
7119
7224
  pool = new AsyncPool(threads, false);
@@ -7137,7 +7242,7 @@ Async::Async(int threads)
7137
7242
 
7138
7243
  Async::Async(Async *parent)
7139
7244
  {
7140
- RG_ASSERT(parent);
7245
+ K_ASSERT(parent);
7141
7246
 
7142
7247
  pool = parent->pool;
7143
7248
  pool->RegisterAsync();
@@ -7195,9 +7300,9 @@ int Async::GetWorkerIdx()
7195
7300
 
7196
7301
  AsyncPool::AsyncPool(int threads, bool leak)
7197
7302
  {
7198
- if (threads > RG_ASYNC_MAX_THREADS) {
7199
- LogError("Async cannot use more than %1 threads", RG_ASYNC_MAX_THREADS);
7200
- threads = RG_ASYNC_MAX_THREADS;
7303
+ if (threads > K_ASYNC_MAX_THREADS) {
7304
+ LogError("Async cannot use more than %1 threads", K_ASYNC_MAX_THREADS);
7305
+ threads = K_ASYNC_MAX_THREADS;
7201
7306
  }
7202
7307
 
7203
7308
  // The first queue is for the main thread
@@ -7301,12 +7406,12 @@ void AsyncPool::AddTask(Async *async, int worker_idx, const std::function<bool()
7301
7406
 
7302
7407
  int prev_pending = pending_tasks++;
7303
7408
 
7304
- if (prev_pending >= RG_ASYNC_MAX_PENDING_TASKS) {
7409
+ if (prev_pending >= K_ASYNC_MAX_PENDING_TASKS) {
7305
7410
  int worker_idx = async_running_worker_idx;
7306
7411
 
7307
7412
  do {
7308
7413
  RunTasks(worker_idx, nullptr);
7309
- } while (pending_tasks >= RG_ASYNC_MAX_PENDING_TASKS);
7414
+ } while (pending_tasks >= K_ASYNC_MAX_PENDING_TASKS);
7310
7415
  } else if (!prev_pending) {
7311
7416
  std::lock_guard<std::mutex> lock_pool(pool_mutex);
7312
7417
 
@@ -7327,7 +7432,7 @@ void AsyncPool::RunWorker(int worker_idx)
7327
7432
  RunTasks(worker_idx, nullptr);
7328
7433
  lock_pool.lock();
7329
7434
 
7330
- std::chrono::duration<int, std::milli> duration(RG_ASYNC_MAX_IDLE_TIME); // Thanks C++
7435
+ std::chrono::duration<int, std::milli> duration(K_ASYNC_MAX_IDLE_TIME); // Thanks C++
7331
7436
  pending_cv.wait_for(lock_pool, duration, [&]() { return !!pending_tasks; });
7332
7437
  }
7333
7438
 
@@ -7341,7 +7446,7 @@ void AsyncPool::RunWorker(int worker_idx)
7341
7446
 
7342
7447
  void AsyncPool::SyncOn(Async *async, bool soon)
7343
7448
  {
7344
- RG_DEFER_C(pool = async_running_pool,
7449
+ K_DEFER_C(pool = async_running_pool,
7345
7450
  worker_idx = async_running_worker_idx) {
7346
7451
  async_running_pool = pool;
7347
7452
  async_running_worker_idx = worker_idx;
@@ -7413,7 +7518,7 @@ void AsyncPool::RunTask(Task *task)
7413
7518
  {
7414
7519
  Async *async = task->async;
7415
7520
 
7416
- RG_DEFER_C(running = async_running_task) { async_running_task = running; };
7521
+ K_DEFER_C(running = async_running_task) { async_running_task = running; };
7417
7522
  async_running_task = true;
7418
7523
 
7419
7524
  pending_tasks--;
@@ -7433,12 +7538,12 @@ void AsyncPool::RunTask(Task *task)
7433
7538
 
7434
7539
  Async::Async(int threads)
7435
7540
  {
7436
- RG_ASSERT(threads);
7541
+ K_ASSERT(threads);
7437
7542
  }
7438
7543
 
7439
7544
  Async::Async(Async *parent)
7440
7545
  {
7441
- RG_ASSERT(parent);
7546
+ K_ASSERT(parent);
7442
7547
  }
7443
7548
 
7444
7549
  Async::~Async()
@@ -7482,38 +7587,47 @@ int Async::GetWorkerCount()
7482
7587
  // Streams
7483
7588
  // ------------------------------------------------------------------------
7484
7589
 
7485
- static StreamReader StdInStream(STDIN_FILENO, "<stdin>");
7486
- static StreamWriter StdOutStream(STDOUT_FILENO, "<stdout>", (int)StreamWriterFlag::LineBuffer);
7487
- static StreamWriter StdErrStream(STDERR_FILENO, "<stderr>", (int)StreamWriterFlag::LineBuffer);
7590
+ static NoDestroy<StreamReader> StdInStream(STDIN_FILENO, "<stdin>");
7591
+ static NoDestroy<StreamWriter> StdOutStream(STDOUT_FILENO, "<stdout>", (int)StreamWriterFlag::LineBuffer);
7592
+ static NoDestroy<StreamWriter> StdErrStream(STDERR_FILENO, "<stderr>", (int)StreamWriterFlag::LineBuffer);
7488
7593
 
7489
- extern StreamReader *const StdIn = &StdInStream;
7490
- extern StreamWriter *const StdOut = &StdOutStream;
7491
- extern StreamWriter *const StdErr = &StdErrStream;
7594
+ extern StreamReader *const StdIn = StdInStream.Get();
7595
+ extern StreamWriter *const StdOut = StdOutStream.Get();
7596
+ extern StreamWriter *const StdErr = StdErrStream.Get();
7492
7597
 
7493
- static CreateDecompressorFunc *DecompressorFunctions[RG_LEN(CompressionTypeNames)];
7494
- static CreateCompressorFunc *CompressorFunctions[RG_LEN(CompressionTypeNames)];
7598
+ static CreateDecompressorFunc *DecompressorFunctions[K_LEN(CompressionTypeNames)];
7599
+ static CreateCompressorFunc *CompressorFunctions[K_LEN(CompressionTypeNames)];
7600
+
7601
+ K_EXIT(FlushStd)
7602
+ {
7603
+ StdOut->Flush();
7604
+ StdErr->Flush();
7605
+ }
7495
7606
 
7496
7607
  void StreamReader::SetDecoder(StreamDecoder *decoder)
7497
7608
  {
7498
- RG_ASSERT(decoder);
7499
- RG_ASSERT(!filename);
7500
- RG_ASSERT(!this->decoder);
7609
+ K_ASSERT(decoder);
7610
+ K_ASSERT(!filename);
7611
+ K_ASSERT(!this->decoder);
7501
7612
 
7502
7613
  this->decoder = decoder;
7503
7614
  }
7504
7615
 
7505
- bool StreamReader::Open(Span<const uint8_t> buf, const char *filename,
7616
+ bool StreamReader::Open(Span<const uint8_t> buf, const char *filename, unsigned int flags,
7506
7617
  CompressionType compression_type)
7507
7618
  {
7508
7619
  Close(true);
7509
7620
 
7510
- RG_DEFER_N(err_guard) { error = true; };
7621
+ K_DEFER_N(err_guard) { error = true; };
7622
+
7623
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7511
7624
  error = false;
7512
7625
  raw_read = 0;
7513
7626
  read_total = 0;
7514
7627
  read_max = -1;
7515
7628
 
7516
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<memory>";
7629
+ K_ASSERT(filename);
7630
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
7517
7631
 
7518
7632
  source.type = SourceType::Memory;
7519
7633
  source.u.memory.buf = buf;
@@ -7526,18 +7640,20 @@ bool StreamReader::Open(Span<const uint8_t> buf, const char *filename,
7526
7640
  return true;
7527
7641
  }
7528
7642
 
7529
- bool StreamReader::Open(int fd, const char *filename, CompressionType compression_type)
7643
+ bool StreamReader::Open(int fd, const char *filename, unsigned int flags, CompressionType compression_type)
7530
7644
  {
7531
7645
  Close(true);
7532
7646
 
7533
- RG_DEFER_N(err_guard) { error = true; };
7647
+ K_DEFER_N(err_guard) { error = true; };
7648
+
7649
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7534
7650
  error = false;
7535
7651
  raw_read = 0;
7536
7652
  read_total = 0;
7537
7653
  read_max = -1;
7538
7654
 
7539
- RG_ASSERT(fd >= 0);
7540
- RG_ASSERT(filename);
7655
+ K_ASSERT(fd >= 0);
7656
+ K_ASSERT(filename);
7541
7657
  this->filename = DuplicateString(filename, &str_alloc).ptr;
7542
7658
 
7543
7659
  source.type = SourceType::File;
@@ -7551,17 +7667,19 @@ bool StreamReader::Open(int fd, const char *filename, CompressionType compressio
7551
7667
  return true;
7552
7668
  }
7553
7669
 
7554
- OpenResult StreamReader::Open(const char *filename, CompressionType compression_type)
7670
+ OpenResult StreamReader::Open(const char *filename, unsigned int flags, CompressionType compression_type)
7555
7671
  {
7556
7672
  Close(true);
7557
7673
 
7558
- RG_DEFER_N(err_guard) { error = true; };
7674
+ K_DEFER_N(err_guard) { error = true; };
7675
+
7676
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7559
7677
  error = false;
7560
7678
  raw_read = 0;
7561
7679
  read_total = 0;
7562
7680
  read_max = -1;
7563
7681
 
7564
- RG_ASSERT(filename);
7682
+ K_ASSERT(filename);
7565
7683
  this->filename = DuplicateString(filename, &str_alloc).ptr;
7566
7684
 
7567
7685
  source.type = SourceType::File;
@@ -7579,18 +7697,21 @@ OpenResult StreamReader::Open(const char *filename, CompressionType compression_
7579
7697
  return OpenResult::Success;
7580
7698
  }
7581
7699
 
7582
- bool StreamReader::Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename,
7700
+ bool StreamReader::Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename, unsigned int flags,
7583
7701
  CompressionType compression_type)
7584
7702
  {
7585
7703
  Close(true);
7586
7704
 
7587
- RG_DEFER_N(err_guard) { error = true; };
7705
+ K_DEFER_N(err_guard) { error = true; };
7706
+
7707
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7588
7708
  error = false;
7589
7709
  raw_read = 0;
7590
7710
  read_total = 0;
7591
7711
  read_max = -1;
7592
7712
 
7593
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<closure>";
7713
+ K_ASSERT(filename);
7714
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
7594
7715
 
7595
7716
  source.type = SourceType::Function;
7596
7717
  new (&source.u.func) std::function<Size(Span<uint8_t>)>(func);
@@ -7604,7 +7725,7 @@ bool StreamReader::Open(const std::function<Size(Span<uint8_t>)> &func, const ch
7604
7725
 
7605
7726
  bool StreamReader::Close(bool implicit)
7606
7727
  {
7607
- RG_ASSERT(implicit || this != StdIn);
7728
+ K_ASSERT(implicit || this != StdIn);
7608
7729
 
7609
7730
  if (decoder) {
7610
7731
  delete decoder;
@@ -7627,6 +7748,7 @@ bool StreamReader::Close(bool implicit)
7627
7748
  bool ret = !filename || !error;
7628
7749
 
7629
7750
  filename = nullptr;
7751
+ lazy = false;
7630
7752
  error = true;
7631
7753
  source.type = SourceType::Memory;
7632
7754
  source.eof = false;
@@ -7673,13 +7795,13 @@ bool StreamReader::Rewind()
7673
7795
 
7674
7796
  int StreamReader::GetDescriptor() const
7675
7797
  {
7676
- RG_ASSERT(source.type == SourceType::File);
7798
+ K_ASSERT(source.type == SourceType::File);
7677
7799
  return source.u.file.fd;
7678
7800
  }
7679
7801
 
7680
7802
  void StreamReader::SetDescriptorOwned(bool owned)
7681
7803
  {
7682
- RG_ASSERT(source.type == SourceType::File);
7804
+ K_ASSERT(source.type == SourceType::File);
7683
7805
  source.u.file.owned = owned;
7684
7806
  }
7685
7807
 
@@ -7720,7 +7842,7 @@ Size StreamReader::Read(Span<uint8_t> out_buf)
7720
7842
  return -1;
7721
7843
  }
7722
7844
 
7723
- if (eof)
7845
+ if (lazy || eof)
7724
7846
  break;
7725
7847
  }
7726
7848
 
@@ -7733,18 +7855,18 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
7733
7855
  if (error) [[unlikely]]
7734
7856
  return -1;
7735
7857
 
7736
- RG_DEFER_NC(buf_guard, buf_len = out_buf->len) { out_buf->RemoveFrom(buf_len); };
7858
+ K_DEFER_NC(buf_guard, buf_len = out_buf->len) { out_buf->RemoveFrom(buf_len); };
7737
7859
 
7738
7860
  // Check virtual memory limits
7739
7861
  {
7740
- Size memory_max = RG_SIZE_MAX - out_buf->len - 1;
7862
+ Size memory_max = K_SIZE_MAX - out_buf->len - 1;
7741
7863
 
7742
7864
  if (memory_max <= 0) [[unlikely]] {
7743
7865
  LogError("Exhausted memory limit reading file '%1'", filename);
7744
7866
  return -1;
7745
7867
  }
7746
7868
 
7747
- RG_ASSERT(max_len);
7869
+ K_ASSERT(max_len);
7748
7870
  max_len = (max_len >= 0) ? std::min(max_len, memory_max) : memory_max;
7749
7871
  }
7750
7872
 
@@ -7772,7 +7894,7 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
7772
7894
  Size total_len = 0;
7773
7895
 
7774
7896
  while (!eof) {
7775
- Size grow = std::min(total_len ? Megabytes(1) : Kibibytes(64), RG_SIZE_MAX - out_buf->len);
7897
+ Size grow = std::min(total_len ? Megabytes(1) : Kibibytes(64), K_SIZE_MAX - out_buf->len);
7776
7898
  out_buf->Grow(grow);
7777
7899
 
7778
7900
  Size read_len = Read(out_buf->Available(), out_buf->end());
@@ -7839,7 +7961,7 @@ bool StreamReader::InitDecompressor(CompressionType type)
7839
7961
  }
7840
7962
 
7841
7963
  decoder = func(this, type);
7842
- RG_ASSERT(decoder);
7964
+ K_ASSERT(decoder);
7843
7965
  }
7844
7966
 
7845
7967
  return true;
@@ -7866,7 +7988,7 @@ Size StreamReader::ReadRaw(Size max_len, void *out_buf)
7866
7988
  max_len = std::min(max_len, (Size)UINT_MAX);
7867
7989
  read_len = _read(source.u.file.fd, out_buf, (unsigned int)max_len);
7868
7990
  #else
7869
- read_len = RG_RESTART_EINTR(read(source.u.file.fd, out_buf, (size_t)max_len), < 0);
7991
+ read_len = K_RESTART_EINTR(read(source.u.file.fd, out_buf, (size_t)max_len), < 0);
7870
7992
  #endif
7871
7993
  if (read_len < 0) {
7872
7994
  LogError("Error while reading file '%1': %2", filename, strerror(errno));
@@ -7892,7 +8014,7 @@ Size StreamReader::ReadRaw(Size max_len, void *out_buf)
7892
8014
 
7893
8015
  StreamDecompressorHelper::StreamDecompressorHelper(CompressionType compression_type, CreateDecompressorFunc *func)
7894
8016
  {
7895
- RG_ASSERT(!DecompressorFunctions[(int)compression_type]);
8017
+ K_ASSERT(!DecompressorFunctions[(int)compression_type]);
7896
8018
  DecompressorFunctions[(int)compression_type] = func;
7897
8019
  }
7898
8020
 
@@ -7908,9 +8030,9 @@ bool LineReader::Next(Span<char> *out_line)
7908
8030
 
7909
8031
  for (;;) {
7910
8032
  if (!view.len) {
7911
- buf.Grow(RG_LINE_READER_STEP_SIZE + 1);
8033
+ buf.Grow(K_LINE_READER_STEP_SIZE + 1);
7912
8034
 
7913
- Size read_len = st->Read(RG_LINE_READER_STEP_SIZE, buf.end());
8035
+ Size read_len = st->Read(K_LINE_READER_STEP_SIZE, buf.end());
7914
8036
  if (read_len < 0) {
7915
8037
  error = true;
7916
8038
  return false;
@@ -7936,7 +8058,7 @@ bool LineReader::Next(Span<char> *out_line)
7936
8058
 
7937
8059
  void LineReader::PushLogFilter()
7938
8060
  {
7939
- RG::PushLogFilter([this](LogLevel level, const char *, const char *msg, FunctionRef<LogFunc> func) {
8061
+ K::PushLogFilter([this](LogLevel level, const char *, const char *msg, FunctionRef<LogFunc> func) {
7940
8062
  char ctx[1024];
7941
8063
 
7942
8064
  if (line_number > 0) {
@@ -7951,23 +8073,24 @@ void LineReader::PushLogFilter()
7951
8073
 
7952
8074
  void StreamWriter::SetEncoder(StreamEncoder *encoder)
7953
8075
  {
7954
- RG_ASSERT(encoder);
7955
- RG_ASSERT(!filename);
7956
- RG_ASSERT(!this->encoder);
8076
+ K_ASSERT(encoder);
8077
+ K_ASSERT(!filename);
8078
+ K_ASSERT(!this->encoder);
7957
8079
 
7958
8080
  this->encoder = encoder;
7959
8081
  }
7960
8082
 
7961
- bool StreamWriter::Open(HeapArray<uint8_t> *mem, const char *filename,
8083
+ bool StreamWriter::Open(HeapArray<uint8_t> *mem, const char *filename, unsigned int,
7962
8084
  CompressionType compression_type, CompressionSpeed compression_speed)
7963
8085
  {
7964
8086
  Close(true);
7965
8087
 
7966
- RG_DEFER_N(err_guard) { error = true; };
8088
+ K_DEFER_N(err_guard) { error = true; };
7967
8089
  error = false;
7968
8090
  raw_written = 0;
7969
8091
 
7970
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<memory>";
8092
+ K_ASSERT(filename);
8093
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
7971
8094
 
7972
8095
  dest.type = DestinationType::Memory;
7973
8096
  dest.u.mem.memory = mem;
@@ -7986,12 +8109,12 @@ bool StreamWriter::Open(int fd, const char *filename, unsigned int flags,
7986
8109
  {
7987
8110
  Close(true);
7988
8111
 
7989
- RG_DEFER_N(err_guard) { error = true; };
8112
+ K_DEFER_N(err_guard) { error = true; };
7990
8113
  error = false;
7991
8114
  raw_written = 0;
7992
8115
 
7993
- RG_ASSERT(fd >= 0);
7994
- RG_ASSERT(filename);
8116
+ K_ASSERT(fd >= 0);
8117
+ K_ASSERT(filename);
7995
8118
  this->filename = DuplicateString(filename, &str_alloc).ptr;
7996
8119
 
7997
8120
  InitFile(flags);
@@ -8011,11 +8134,11 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
8011
8134
  {
8012
8135
  Close(true);
8013
8136
 
8014
- RG_DEFER_N(err_guard) { error = true; };
8137
+ K_DEFER_N(err_guard) { error = true; };
8015
8138
  error = false;
8016
8139
  raw_written = 0;
8017
8140
 
8018
- RG_ASSERT(filename);
8141
+ K_ASSERT(filename);
8019
8142
  this->filename = DuplicateString(filename, &str_alloc).ptr;
8020
8143
 
8021
8144
  InitFile(flags);
@@ -8041,7 +8164,7 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
8041
8164
 
8042
8165
  if (has_proc) {
8043
8166
  const char *dirname = DuplicateString(directory, &str_alloc).ptr;
8044
- dest.u.file.fd = RG_RESTART_EINTR(open(dirname, O_WRONLY | O_TMPFILE | O_CLOEXEC, 0644), < 0);
8167
+ dest.u.file.fd = K_RESTART_EINTR(open(dirname, O_WRONLY | O_TMPFILE | O_CLOEXEC, 0644), < 0);
8045
8168
 
8046
8169
  if (dest.u.file.fd >= 0) {
8047
8170
  dest.u.file.owned = true;
@@ -8054,7 +8177,7 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
8054
8177
  #endif
8055
8178
 
8056
8179
  if (!dest.u.file.owned) {
8057
- const char *basename = SplitStrReverseAny(filename, RG_PATH_SEPARATORS).ptr;
8180
+ const char *basename = SplitStrReverseAny(filename, K_PATH_SEPARATORS).ptr;
8058
8181
 
8059
8182
  dest.u.file.tmp_filename = CreateUniqueFile(directory, basename, ".tmp", &str_alloc, &dest.u.file.fd);
8060
8183
  if (!dest.u.file.tmp_filename)
@@ -8081,16 +8204,17 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
8081
8204
  return true;
8082
8205
  }
8083
8206
 
8084
- bool StreamWriter::Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename,
8207
+ bool StreamWriter::Open(const std::function<bool(Span<const uint8_t>)> &func, const char *filename, unsigned int,
8085
8208
  CompressionType compression_type, CompressionSpeed compression_speed)
8086
8209
  {
8087
8210
  Close(true);
8088
8211
 
8089
- RG_DEFER_N(err_guard) { error = true; };
8212
+ K_DEFER_N(err_guard) { error = true; };
8090
8213
  error = false;
8091
8214
  raw_written = 0;
8092
8215
 
8093
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<closure>";
8216
+ K_ASSERT(filename);
8217
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
8094
8218
 
8095
8219
  dest.type = DestinationType::Function;
8096
8220
  new (&dest.u.func) std::function<bool(Span<const uint8_t>)>(func);
@@ -8185,12 +8309,12 @@ bool StreamWriter::Flush()
8185
8309
  case DestinationType::Function: return true;
8186
8310
  }
8187
8311
 
8188
- RG_UNREACHABLE();
8312
+ K_UNREACHABLE();
8189
8313
  }
8190
8314
 
8191
8315
  int StreamWriter::GetDescriptor() const
8192
8316
  {
8193
- RG_ASSERT(dest.type == DestinationType::BufferedFile ||
8317
+ K_ASSERT(dest.type == DestinationType::BufferedFile ||
8194
8318
  dest.type == DestinationType::LineFile ||
8195
8319
  dest.type == DestinationType::DirectFile);
8196
8320
 
@@ -8199,7 +8323,7 @@ int StreamWriter::GetDescriptor() const
8199
8323
 
8200
8324
  void StreamWriter::SetDescriptorOwned(bool owned)
8201
8325
  {
8202
- RG_ASSERT(dest.type == DestinationType::BufferedFile ||
8326
+ K_ASSERT(dest.type == DestinationType::BufferedFile ||
8203
8327
  dest.type == DestinationType::LineFile ||
8204
8328
  dest.type == DestinationType::DirectFile);
8205
8329
 
@@ -8225,8 +8349,8 @@ bool StreamWriter::Write(Span<const uint8_t> buf)
8225
8349
 
8226
8350
  bool StreamWriter::Close(bool implicit)
8227
8351
  {
8228
- RG_ASSERT(implicit || this != StdOut);
8229
- RG_ASSERT(implicit || this != StdErr);
8352
+ K_ASSERT(implicit || this != StdOut);
8353
+ K_ASSERT(implicit || this != StdErr);
8230
8354
 
8231
8355
  if (encoder) {
8232
8356
  error = error || !encoder->Finalize();
@@ -8285,7 +8409,7 @@ bool StreamWriter::Close(bool implicit)
8285
8409
  // a temporary file and let RenameFile() handle the final step. Should be rare!
8286
8410
  if (!linked) {
8287
8411
  Span<const char> directory = GetPathDirectory(filename);
8288
- const char *basename = SplitStrReverseAny(filename, RG_PATH_SEPARATORS).ptr;
8412
+ const char *basename = SplitStrReverseAny(filename, K_PATH_SEPARATORS).ptr;
8289
8413
 
8290
8414
  dest.u.file.tmp_filename = CreateUniquePath(directory, basename, ".tmp", &str_alloc, [&](const char *path) {
8291
8415
  return !linkat(AT_FDCWD, proc, AT_FDCWD, path, AT_SYMLINK_FOLLOW);
@@ -8330,7 +8454,7 @@ bool StreamWriter::Close(bool implicit)
8330
8454
  UnlinkFile(filename);
8331
8455
  }
8332
8456
 
8333
- MemSet(&dest.u.file, 0, RG_SIZE(dest.u.file));
8457
+ MemSet(&dest.u.file, 0, K_SIZE(dest.u.file));
8334
8458
  } break;
8335
8459
 
8336
8460
  case DestinationType::Function: {
@@ -8354,9 +8478,9 @@ void StreamWriter::InitFile(unsigned int flags)
8354
8478
  bool direct = (flags & (int)StreamWriterFlag::NoBuffer);
8355
8479
  bool line = (flags & (int)StreamWriterFlag::LineBuffer);
8356
8480
 
8357
- RG_ASSERT(!direct || !line);
8481
+ K_ASSERT(!direct || !line);
8358
8482
 
8359
- MemSet(&dest.u.file, 0, RG_SIZE(dest.u.file));
8483
+ MemSet(&dest.u.file, 0, K_SIZE(dest.u.file));
8360
8484
 
8361
8485
  if (direct) {
8362
8486
  dest.type = DestinationType::DirectFile;
@@ -8371,15 +8495,15 @@ void StreamWriter::InitFile(unsigned int flags)
8371
8495
 
8372
8496
  bool StreamWriter::FlushBuffer()
8373
8497
  {
8374
- RG_ASSERT(!error);
8375
- RG_ASSERT(dest.type == DestinationType::BufferedFile ||
8498
+ K_ASSERT(!error);
8499
+ K_ASSERT(dest.type == DestinationType::BufferedFile ||
8376
8500
  dest.type == DestinationType::LineFile);
8377
8501
 
8378
8502
  while (dest.u.file.buf_used) {
8379
8503
  #if defined(_WIN32)
8380
8504
  Size write_len = _write(dest.u.file.fd, dest.u.file.buf.ptr, (unsigned int)dest.u.file.buf_used);
8381
8505
  #else
8382
- Size write_len = RG_RESTART_EINTR(write(dest.u.file.fd, dest.u.file.buf.ptr, (size_t)dest.u.file.buf_used), < 0);
8506
+ Size write_len = K_RESTART_EINTR(write(dest.u.file.fd, dest.u.file.buf.ptr, (size_t)dest.u.file.buf_used), < 0);
8383
8507
  #endif
8384
8508
 
8385
8509
  if (write_len < 0) {
@@ -8410,7 +8534,7 @@ bool StreamWriter::InitCompressor(CompressionType type, CompressionSpeed speed)
8410
8534
  }
8411
8535
 
8412
8536
  encoder = func(this, type, speed);
8413
- RG_ASSERT(encoder);
8537
+ K_ASSERT(encoder);
8414
8538
  }
8415
8539
 
8416
8540
  return true;
@@ -8497,7 +8621,7 @@ bool StreamWriter::WriteRaw(Span<const uint8_t> buf)
8497
8621
  unsigned int int_len = (unsigned int)std::min(buf.len, (Size)UINT_MAX);
8498
8622
  Size write_len = _write(dest.u.file.fd, buf.ptr, int_len);
8499
8623
  #else
8500
- Size write_len = RG_RESTART_EINTR(write(dest.u.file.fd, buf.ptr, (size_t)buf.len), < 0);
8624
+ Size write_len = K_RESTART_EINTR(write(dest.u.file.fd, buf.ptr, (size_t)buf.len), < 0);
8501
8625
  #endif
8502
8626
 
8503
8627
  if (write_len < 0) {
@@ -8532,14 +8656,14 @@ bool StreamWriter::WriteRaw(Span<const uint8_t> buf)
8532
8656
 
8533
8657
  StreamCompressorHelper::StreamCompressorHelper(CompressionType compression_type, CreateCompressorFunc *func)
8534
8658
  {
8535
- RG_ASSERT(!CompressorFunctions[(int)compression_type]);
8659
+ K_ASSERT(!CompressorFunctions[(int)compression_type]);
8536
8660
  CompressorFunctions[(int)compression_type] = func;
8537
8661
  }
8538
8662
 
8539
8663
  bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer, Span<uint8_t> buf,
8540
8664
  FunctionRef<void(int64_t, int64_t)> progress)
8541
8665
  {
8542
- RG_ASSERT(buf.len >= Kibibytes(2));
8666
+ K_ASSERT(buf.len >= Kibibytes(2));
8543
8667
 
8544
8668
  if (!reader->IsValid())
8545
8669
  return false;
@@ -8586,7 +8710,7 @@ IniParser::LineType IniParser::FindNextLine(IniProperty *out_prop)
8586
8710
  if (error) [[unlikely]]
8587
8711
  return LineType::Exit;
8588
8712
 
8589
- RG_DEFER_N(err_guard) { error = true; };
8713
+ K_DEFER_N(err_guard) { error = true; };
8590
8714
 
8591
8715
  Span<char> line;
8592
8716
  while (reader.Next(&line)) {
@@ -8680,7 +8804,7 @@ bool ReloadAssets()
8680
8804
  SplitStrReverse(prefix, '.', &prefix);
8681
8805
  #endif
8682
8806
 
8683
- Fmt(assets_filename, "%1_assets%2", prefix, RG_SHARED_LIBRARY_EXTENSION);
8807
+ Fmt(assets_filename, "%1_assets%2", prefix, K_SHARED_LIBRARY_EXTENSION);
8684
8808
  }
8685
8809
 
8686
8810
  // Check library time
@@ -8709,7 +8833,7 @@ bool ReloadAssets()
8709
8833
  LogError("Cannot load library '%1'", assets_filename);
8710
8834
  return false;
8711
8835
  }
8712
- RG_DEFER { FreeLibrary(h); };
8836
+ K_DEFER { FreeLibrary(h); };
8713
8837
 
8714
8838
  lib_assets = (const Span<const AssetInfo> *)(void *)GetProcAddress(h, "EmbedAssets");
8715
8839
  #else
@@ -8718,12 +8842,12 @@ bool ReloadAssets()
8718
8842
  LogError("Cannot load library '%1': %2", assets_filename, dlerror());
8719
8843
  return false;
8720
8844
  }
8721
- RG_DEFER { dlclose(h); };
8845
+ K_DEFER { dlclose(h); };
8722
8846
 
8723
8847
  lib_assets = (const Span<const AssetInfo> *)dlsym(h, "EmbedAssets");
8724
8848
  #endif
8725
8849
  if (!lib_assets) {
8726
- LogError("Cannot find symbol '%1' in library '%2'", "EmbedAssets", assets_filename);
8850
+ LogError("Cannot find symbol 'EmbedAssets' in library '%1'", assets_filename);
8727
8851
  return false;
8728
8852
  }
8729
8853
 
@@ -8754,7 +8878,7 @@ Span<const AssetInfo> GetEmbedAssets()
8754
8878
  {
8755
8879
  if (!assets_ready) {
8756
8880
  ReloadAssets();
8757
- RG_ASSERT(assets_ready);
8881
+ K_ASSERT(assets_ready);
8758
8882
  }
8759
8883
 
8760
8884
  return assets;
@@ -8764,7 +8888,7 @@ const AssetInfo *FindEmbedAsset(const char *name)
8764
8888
  {
8765
8889
  if (!assets_ready) {
8766
8890
  ReloadAssets();
8767
- RG_ASSERT(assets_ready);
8891
+ K_ASSERT(assets_ready);
8768
8892
  }
8769
8893
 
8770
8894
  return assets_map.FindValue(name, nullptr);
@@ -8823,10 +8947,10 @@ bool PatchFile(StreamReader *reader, StreamWriter *writer,
8823
8947
  bool PatchFile(Span<const uint8_t> data, StreamWriter *writer,
8824
8948
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8825
8949
  {
8826
- StreamReader reader(data, nullptr);
8950
+ StreamReader reader(data, "<asset>");
8827
8951
 
8828
8952
  if (!PatchFile(&reader, writer, func)) {
8829
- RG_ASSERT(reader.IsValid());
8953
+ K_ASSERT(reader.IsValid());
8830
8954
  return false;
8831
8955
  }
8832
8956
 
@@ -8836,10 +8960,10 @@ bool PatchFile(Span<const uint8_t> data, StreamWriter *writer,
8836
8960
  bool PatchFile(const AssetInfo &asset, StreamWriter *writer,
8837
8961
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8838
8962
  {
8839
- StreamReader reader(asset.data, nullptr, asset.compression_type);
8963
+ StreamReader reader(asset.data, "<asset>", 0, asset.compression_type);
8840
8964
 
8841
8965
  if (!PatchFile(&reader, writer, func)) {
8842
- RG_ASSERT(reader.IsValid());
8966
+ K_ASSERT(reader.IsValid());
8843
8967
  return false;
8844
8968
  }
8845
8969
 
@@ -8849,15 +8973,15 @@ bool PatchFile(const AssetInfo &asset, StreamWriter *writer,
8849
8973
  Span<const uint8_t> PatchFile(Span<const uint8_t> data, Allocator *alloc,
8850
8974
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8851
8975
  {
8852
- RG_ASSERT(alloc);
8976
+ K_ASSERT(alloc);
8853
8977
 
8854
8978
  HeapArray<uint8_t> buf(alloc);
8855
- StreamWriter writer(&buf, nullptr);
8979
+ StreamWriter writer(&buf, "<asset>");
8856
8980
 
8857
8981
  PatchFile(data, &writer, func);
8858
8982
 
8859
8983
  bool success = writer.Close();
8860
- RG_ASSERT(success);
8984
+ K_ASSERT(success);
8861
8985
 
8862
8986
  buf.Grow(1);
8863
8987
  buf.ptr[buf.len] = 0;
@@ -8868,15 +8992,15 @@ Span<const uint8_t> PatchFile(Span<const uint8_t> data, Allocator *alloc,
8868
8992
  Span<const uint8_t> PatchFile(const AssetInfo &asset, Allocator *alloc,
8869
8993
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8870
8994
  {
8871
- RG_ASSERT(alloc);
8995
+ K_ASSERT(alloc);
8872
8996
 
8873
8997
  HeapArray<uint8_t> buf(alloc);
8874
- StreamWriter writer(&buf, nullptr, asset.compression_type);
8998
+ StreamWriter writer(&buf, "<asset>", 0, asset.compression_type);
8875
8999
 
8876
9000
  PatchFile(asset, &writer, func);
8877
9001
 
8878
9002
  bool success = writer.Close();
8879
- RG_ASSERT(success);
9003
+ K_ASSERT(success);
8880
9004
 
8881
9005
  buf.Grow(1);
8882
9006
  buf.ptr[buf.len] = 0;
@@ -8892,7 +9016,108 @@ Span<const char> PatchFile(Span<const char> data, Allocator *alloc,
8892
9016
  }
8893
9017
 
8894
9018
  // ------------------------------------------------------------------------
8895
- // Option parser
9019
+ // Translations
9020
+ // ------------------------------------------------------------------------
9021
+
9022
+ typedef HashMap<const char *, const char *> TranslationMap;
9023
+
9024
+ static HeapArray<TranslationTable> i18n_tables;
9025
+ static NoDestroy<HeapArray<TranslationMap>> i18n_maps;
9026
+ static HashMap<Span<const char> , const TranslationTable *> i18n_locales;
9027
+
9028
+ static const TranslationMap *i18n_default;
9029
+ static thread_local const TranslationMap *i18n_thread = i18n_default;
9030
+
9031
+ static void SetDefaultLocale()
9032
+ {
9033
+ if (i18n_default)
9034
+ return;
9035
+
9036
+ // Obey environment settings, even on Windows, for easy override
9037
+ {
9038
+ // Yeah this order makes perfect sense. Don't ask.
9039
+ static const char *const EnvVariables[] = { "LANGUAGE", "LC_MESSAGES", "LC_ALL", "LANG" };
9040
+
9041
+ for (const char *variable: EnvVariables) {
9042
+ const char *env = GetEnv(variable);
9043
+
9044
+ if (env) {
9045
+ ChangeThreadLocale(env);
9046
+ i18n_default = i18n_thread;
9047
+
9048
+ if (i18n_default)
9049
+ return;
9050
+ }
9051
+ }
9052
+ }
9053
+
9054
+ #if defined(_WIN32)
9055
+ {
9056
+ wchar_t buffer[16384];
9057
+ unsigned long languages = 0;
9058
+ unsigned long size = K_LEN(buffer);
9059
+
9060
+ if (GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &languages, buffer, &size)) {
9061
+ if (languages) {
9062
+ char lang[256] = {};
9063
+ ConvertWin32WideToUtf8(buffer, lang);
9064
+
9065
+ ChangeThreadLocale(lang);
9066
+ i18n_default = i18n_thread;
9067
+
9068
+ if (i18n_default)
9069
+ return;
9070
+ }
9071
+ } else {
9072
+ LogError("Failed to retrieve preferred Windows UI language: %1", GetWin32ErrorString());
9073
+ }
9074
+ }
9075
+ #endif
9076
+ }
9077
+
9078
+ void InitLocales(Span<const TranslationTable> tables)
9079
+ {
9080
+ K_ASSERT(!i18n_tables.len);
9081
+
9082
+ for (const TranslationTable &table: tables) {
9083
+ i18n_tables.Append(table);
9084
+
9085
+ TranslationMap *map = i18n_maps->AppendDefault();
9086
+
9087
+ for (const TranslationTable::Pair &pair: table.messages) {
9088
+ map->Set(pair.key, pair.value);
9089
+ }
9090
+ }
9091
+ for (const TranslationTable &table: i18n_tables) {
9092
+ i18n_locales.Set(table.language, &table);
9093
+ }
9094
+
9095
+ SetDefaultLocale();
9096
+ }
9097
+
9098
+ void ChangeThreadLocale(const char *name)
9099
+ {
9100
+ Span<const char> lang = name ? SplitStrAny(name, "_-") : "";
9101
+ const TranslationTable *table = i18n_locales.FindValue(lang, nullptr);
9102
+
9103
+ if (table) {
9104
+ Size idx = table - i18n_tables.ptr;
9105
+ i18n_thread = &(*i18n_maps)[idx];
9106
+ } else {
9107
+ i18n_thread = i18n_default;
9108
+ }
9109
+ }
9110
+
9111
+ const char *T(const char *key)
9112
+ {
9113
+ if (!i18n_thread)
9114
+ return key;
9115
+
9116
+ return i18n_thread->FindValue(key, key);
9117
+ }
9118
+
9119
+ // ------------------------------------------------------------------------
9120
+ // Options
8896
9121
  // ------------------------------------------------------------------------
8897
9122
 
8898
9123
  static inline bool IsOption(const char *arg)
@@ -8961,8 +9186,8 @@ const char *OptionParser::Next()
8961
9186
  // option up to '=' in our buffer. And store the part after '=' as the
8962
9187
  // current value.
8963
9188
  Size len = needle - opt;
8964
- if (len > RG_SIZE(buf) - 1) {
8965
- len = RG_SIZE(buf) - 1;
9189
+ if (len > K_SIZE(buf) - 1) {
9190
+ len = K_SIZE(buf) - 1;
8966
9191
  }
8967
9192
  MemCpy(buf, opt, len);
8968
9193
  buf[len] = 0;
@@ -9044,8 +9269,8 @@ void OptionParser::ConsumeNonOptions(HeapArray<const char *> *non_options)
9044
9269
 
9045
9270
  bool OptionParser::Test(const char *test1, const char *test2, OptionType type)
9046
9271
  {
9047
- RG_ASSERT(test1 && IsOption(test1));
9048
- RG_ASSERT(!test2 || IsOption(test2));
9272
+ K_ASSERT(test1 && IsOption(test1));
9273
+ K_ASSERT(!test2 || IsOption(test2));
9049
9274
 
9050
9275
  if (TestStr(test1, current_option) || (test2 && TestStr(test2, current_option))) {
9051
9276
  switch (type) {
@@ -9176,11 +9401,11 @@ bool ConsolePrompter::Read(Span<const char> *out_str)
9176
9401
  #if !defined(_WIN32) && !defined(__wasm__)
9177
9402
  struct sigaction old_sa;
9178
9403
  IgnoreSigWinch(&old_sa);
9179
- RG_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9404
+ K_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9180
9405
  #endif
9181
9406
 
9182
9407
  if (FileIsVt100(STDERR_FILENO) && EnableRawMode()) {
9183
- RG_DEFER {
9408
+ K_DEFER {
9184
9409
  Print(StdErr, "%!0");
9185
9410
  DisableRawMode();
9186
9411
  };
@@ -9193,16 +9418,16 @@ bool ConsolePrompter::Read(Span<const char> *out_str)
9193
9418
 
9194
9419
  Size ConsolePrompter::ReadEnum(Span<const PromptChoice> choices, Size value)
9195
9420
  {
9196
- RG_ASSERT(value < choices.len);
9421
+ K_ASSERT(value < choices.len);
9197
9422
 
9198
9423
  #if !defined(_WIN32) && !defined(__wasm__)
9199
9424
  struct sigaction old_sa;
9200
9425
  IgnoreSigWinch(&old_sa);
9201
- RG_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9426
+ K_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9202
9427
  #endif
9203
9428
 
9204
9429
  if (FileIsVt100(STDERR_FILENO) && EnableRawMode()) {
9205
- RG_DEFER {
9430
+ K_DEFER {
9206
9431
  Print(StdErr, "%!0");
9207
9432
  DisableRawMode();
9208
9433
  };
@@ -9235,7 +9460,7 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
9235
9460
  {
9236
9461
  StdErr->Flush();
9237
9462
 
9238
- prompt_columns = ComputeWidth(prompt);
9463
+ prompt_columns = ComputeUnicodeWidth(prompt) + 1;
9239
9464
  str_offset = str.len;
9240
9465
 
9241
9466
  RenderRaw();
@@ -9252,7 +9477,7 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
9252
9477
  LocalArray<char, 16> buf;
9253
9478
 
9254
9479
  const auto match_escape = [&](const char *seq) {
9255
- RG_ASSERT(strlen(seq) < RG_SIZE(buf.data));
9480
+ K_ASSERT(strlen(seq) < K_SIZE(buf.data));
9256
9481
 
9257
9482
  for (Size i = 0; seq[i]; i++) {
9258
9483
  if (i >= buf.len) {
@@ -9481,7 +9706,7 @@ Size ConsolePrompter::ReadRawEnum(Span<const PromptChoice> choices, Size value)
9481
9706
  LocalArray<char, 16> buf;
9482
9707
 
9483
9708
  const auto match_escape = [&](const char *seq) {
9484
- RG_ASSERT(strlen(seq) < RG_SIZE(buf.data));
9709
+ K_ASSERT(strlen(seq) < K_SIZE(buf.data));
9485
9710
 
9486
9711
  for (Size i = 0; seq[i]; i++) {
9487
9712
  if (i >= buf.len) {
@@ -9561,7 +9786,7 @@ Size ConsolePrompter::ReadRawEnum(Span<const PromptChoice> choices, Size value)
9561
9786
 
9562
9787
  bool ConsolePrompter::ReadBuffered(Span<const char> *out_str)
9563
9788
  {
9564
- prompt_columns = ComputeWidth(prompt);
9789
+ prompt_columns = ComputeUnicodeWidth(prompt) + 1;
9565
9790
 
9566
9791
  RenderBuffered();
9567
9792
 
@@ -9692,8 +9917,8 @@ Size ConsolePrompter::FindBackward(Size offset, const char *chars)
9692
9917
 
9693
9918
  void ConsolePrompter::Delete(Size start, Size end)
9694
9919
  {
9695
- RG_ASSERT(start >= 0);
9696
- RG_ASSERT(end >= start && end <= str.len);
9920
+ K_ASSERT(start >= 0);
9921
+ K_ASSERT(end >= start && end <= str.len);
9697
9922
 
9698
9923
  MemMove(str.ptr + start, str.ptr + end, str.len - end);
9699
9924
  str.len -= end - start;
@@ -9710,15 +9935,16 @@ void ConsolePrompter::FormatChoices(Span<const PromptChoice> choices, Size value
9710
9935
  int align = 0;
9711
9936
 
9712
9937
  for (const PromptChoice &choice: choices) {
9713
- align = std::max(align, (int)strlen(choice.str));
9938
+ align = std::max(align, (int)ComputeUnicodeWidth(choice.str));
9714
9939
  }
9715
9940
 
9716
9941
  str.RemoveFrom(0);
9717
9942
  str.Append('\n');
9718
9943
  for (Size i = 0; i < choices.len; i++) {
9719
9944
  const PromptChoice &choice = choices[i];
9945
+ int pad = align - ComputeUnicodeWidth(choice.str);
9720
9946
 
9721
- Fmt(&str, " [%1] %2 ", choice.c, FmtArg(choice.str).Pad(align));
9947
+ Fmt(&str, " [%1] %2%3 ", choice.c, choice.str, FmtArg(' ').Repeat(pad));
9722
9948
  if (i == value) {
9723
9949
  str_offset = str.len;
9724
9950
  }
@@ -9731,7 +9957,7 @@ void ConsolePrompter::RenderRaw()
9731
9957
  columns = GetConsoleSize().x;
9732
9958
  rows = 0;
9733
9959
 
9734
- int mask_columns = mask ? ComputeWidth(mask) : 0;
9960
+ int mask_columns = mask ? ComputeUnicodeWidth(mask) : 0;
9735
9961
 
9736
9962
  // Hide cursor during refresh
9737
9963
  StdErr->Write("\x1B[?25l");
@@ -9744,7 +9970,7 @@ void ConsolePrompter::RenderRaw()
9744
9970
  Size i = 0;
9745
9971
  int x2 = prompt_columns;
9746
9972
 
9747
- Print(StdErr, "\r%!0%1%!..+", prompt);
9973
+ Print(StdErr, "\r%!0%1 %!..+", prompt);
9748
9974
 
9749
9975
  for (;;) {
9750
9976
  if (i == str_offset) {
@@ -9755,7 +9981,7 @@ void ConsolePrompter::RenderRaw()
9755
9981
  break;
9756
9982
 
9757
9983
  Size bytes = std::min((Size)CountUtf8Bytes(str[i]), str.len - i);
9758
- int width = mask ? mask_columns : ComputeWidth(str.Take(i, bytes));
9984
+ int width = mask ? mask_columns : ComputeUnicodeWidth(str.Take(i, bytes));
9759
9985
 
9760
9986
  if (x2 + width >= columns || str[i] == '\n') {
9761
9987
  FmtArg prefix = FmtArg(' ').Repeat(prompt_columns - 1);
@@ -9799,7 +10025,7 @@ void ConsolePrompter::RenderBuffered()
9799
10025
  Span<const char> remain = str;
9800
10026
  Span<const char> line = SplitStr(remain, '\n', &remain);
9801
10027
 
9802
- Print(StdErr, "%1%2", prompt, line);
10028
+ Print(StdErr, "%1 %2", prompt, line);
9803
10029
  while (remain.len) {
9804
10030
  line = SplitStr(remain, '\n', &remain);
9805
10031
  Print(StdErr, "\n%1%2", FmtArg(' ').Repeat(prompt_columns), line);
@@ -9966,25 +10192,6 @@ error:
9966
10192
  #endif
9967
10193
  }
9968
10194
 
9969
- int ConsolePrompter::ComputeWidth(Span<const char> str)
9970
- {
9971
- Size i = 0;
9972
- int width = 0;
9973
-
9974
- while (i < str.len) {
9975
- int32_t uc;
9976
- Size bytes = DecodeUtf8(str, i, &uc);
9977
-
9978
- if (!bytes) [[unlikely]]
9979
- return false;
9980
-
9981
- i += bytes;
9982
- width += ComputeCharacterWidth(uc);
9983
- }
9984
-
9985
- return width;
9986
- }
9987
-
9988
10195
  void ConsolePrompter::EnsureNulTermination()
9989
10196
  {
9990
10197
  str.Grow(1);
@@ -9993,7 +10200,7 @@ void ConsolePrompter::EnsureNulTermination()
9993
10200
 
9994
10201
  const char *Prompt(const char *prompt, const char *default_value, const char *mask, Allocator *alloc)
9995
10202
  {
9996
- RG_ASSERT(alloc);
10203
+ K_ASSERT(alloc);
9997
10204
 
9998
10205
  ConsolePrompter prompter;
9999
10206
 
@@ -10013,7 +10220,7 @@ const char *Prompt(const char *prompt, const char *default_value, const char *ma
10013
10220
 
10014
10221
  Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value)
10015
10222
  {
10016
- #if defined(RG_DEBUG)
10223
+ #if defined(K_DEBUG)
10017
10224
  {
10018
10225
  HashSet<char> keys;
10019
10226
 
@@ -10022,7 +10229,7 @@ Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value
10022
10229
  }
10023
10230
 
10024
10231
  bool duplicates = (keys.table.count < choices.len);
10025
- RG_ASSERT(!duplicates);
10232
+ K_ASSERT(!duplicates);
10026
10233
  }
10027
10234
  #endif
10028
10235
 
@@ -10035,7 +10242,7 @@ Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value
10035
10242
  Size PromptEnum(const char *prompt, Span<const char *const> strings, Size value)
10036
10243
  {
10037
10244
  static const char literals[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
10038
- RG_ASSERT(strings.len <= RG_LEN(literals));
10245
+ K_ASSERT(strings.len <= K_LEN(literals));
10039
10246
 
10040
10247
  HeapArray<PromptChoice> choices;
10041
10248
 
@@ -10090,7 +10297,7 @@ bool CanCompressFile(const char *filename)
10090
10297
  const char *ptr = GetPathExtension(filename).ptr;
10091
10298
 
10092
10299
  Size i = 0;
10093
- while (i < RG_SIZE(extension) - 1 && ptr[i]) {
10300
+ while (i < K_SIZE(extension) - 1 && ptr[i]) {
10094
10301
  extension[i] = LowerAscii(ptr[i]);
10095
10302
  i++;
10096
10303
  }
@@ -10132,10 +10339,27 @@ bool CanCompressFile(const char *filename)
10132
10339
  // Unicode
10133
10340
  // ------------------------------------------------------------------------
10134
10341
 
10342
+ bool IsValidUtf8(Span<const char> str)
10343
+ {
10344
+ Size i = 0;
10345
+
10346
+ while (i < str.len) {
10347
+ int32_t uc;
10348
+ Size bytes = DecodeUtf8(str, i, &uc);
10349
+
10350
+ if (!bytes) [[unlikely]]
10351
+ return false;
10352
+
10353
+ i += bytes;
10354
+ }
10355
+
10356
+ return i == str.len;
10357
+ }
10358
+
10135
10359
  static bool TestUnicodeTable(Span<const int32_t> table, int32_t uc)
10136
10360
  {
10137
- RG_ASSERT(table.len > 0);
10138
- RG_ASSERT(table.len % 2 == 0);
10361
+ K_ASSERT(table.len > 0);
10362
+ K_ASSERT(table.len % 2 == 0);
10139
10363
 
10140
10364
  auto it = std::upper_bound(table.begin(), table.end(), uc,
10141
10365
  [](int32_t uc, int32_t x) { return uc < x; });
@@ -10145,10 +10369,11 @@ static bool TestUnicodeTable(Span<const int32_t> table, int32_t uc)
10145
10369
  return idx & 0x1;
10146
10370
  }
10147
10371
 
10148
- int ComputeCharacterWidth(int32_t uc)
10372
+ static inline int ComputeCharacterWidth(int32_t uc)
10149
10373
  {
10150
- if (uc < 32)
10151
- return 0;
10374
+ // Fast path
10375
+ if (uc < 128)
10376
+ return (uc >= 32) ? 1 : 0;
10152
10377
 
10153
10378
  if (TestUnicodeTable(WcWidthNull, uc))
10154
10379
  return 0;
@@ -10158,6 +10383,25 @@ int ComputeCharacterWidth(int32_t uc)
10158
10383
  return 1;
10159
10384
  }
10160
10385
 
10386
+ int ComputeUnicodeWidth(Span<const char> str)
10387
+ {
10388
+ Size i = 0;
10389
+ int width = 0;
10390
+
10391
+ while (i < str.len) {
10392
+ int32_t uc;
10393
+ Size bytes = DecodeUtf8(str, i, &uc);
10394
+
10395
+ if (!bytes) [[unlikely]]
10396
+ return false;
10397
+
10398
+ i += bytes;
10399
+ width += ComputeCharacterWidth(uc);
10400
+ }
10401
+
10402
+ return width;
10403
+ }
10404
+
10161
10405
  bool IsXidStart(int32_t uc)
10162
10406
  {
10163
10407
  if (IsAsciiAlpha(uc))
@@ -10190,7 +10434,7 @@ uint32_t CRC32(uint32_t state, Span<const uint8_t> buf)
10190
10434
  {
10191
10435
  state = ~state;
10192
10436
 
10193
- Size right = buf.len & (RG_SIZE_MAX - 3);
10437
+ Size right = buf.len & (K_SIZE_MAX - 3);
10194
10438
 
10195
10439
  for (Size i = 0; i < right; i += 4) {
10196
10440
  state = (state >> 8) ^ Crc32Table[(state ^ buf[i + 0]) & 0xFF];
@@ -10209,7 +10453,7 @@ uint32_t CRC32C(uint32_t state, Span<const uint8_t> buf)
10209
10453
  {
10210
10454
  state = ~state;
10211
10455
 
10212
- Size right = buf.len & (RG_SIZE_MAX - 3);
10456
+ Size right = buf.len & (K_SIZE_MAX - 3);
10213
10457
 
10214
10458
  for (Size i = 0; i < right; i += 4) {
10215
10459
  state = (state >> 8) ^ Crc32CTable[(state ^ buf[i + 0]) & 0xFF];
@@ -10255,16 +10499,12 @@ uint64_t CRC64xz(uint64_t state, Span<const uint8_t> buf)
10255
10499
  {
10256
10500
  state = ~state;
10257
10501
 
10258
- Size left = std::min(buf.len, (Size)(AlignUp(buf.ptr, 16) - buf.ptr));
10259
- Size right = std::max(left, (Size)(AlignDown(buf.end(), 16) - buf.ptr));
10502
+ Size len16 = buf.len / 16 * 16;
10260
10503
 
10261
- for (Size i = 0; i < left; i++) {
10262
- state = XzUpdate1(state, buf[i]);
10263
- }
10264
- for (Size i = left; i < right; i += 16) {
10504
+ for (Size i = 0; i < len16; i += 16) {
10265
10505
  state = XzUpdate16(state, buf.ptr + i);
10266
10506
  }
10267
- for (Size i = right; i < buf.len; i++) {
10507
+ for (Size i = len16; i < buf.len; i++) {
10268
10508
  state = XzUpdate1(state, buf[i]);
10269
10509
  }
10270
10510
 
@@ -10302,16 +10542,12 @@ uint64_t CRC64nvme(uint64_t state, Span<const uint8_t> buf)
10302
10542
  {
10303
10543
  state = ~state;
10304
10544
 
10305
- Size left = std::min(buf.len, (Size)(AlignUp(buf.ptr, 16) - buf.ptr));
10306
- Size right = std::max(left, (Size)(AlignDown(buf.end(), 16) - buf.ptr));
10545
+ Size len16 = buf.len / 16 * 16;
10307
10546
 
10308
- for (Size i = 0; i < left; i++) {
10309
- state = NvmeUpdate1(state, buf[i]);
10310
- }
10311
- for (Size i = left; i < right; i += 16) {
10547
+ for (Size i = 0; i < len16; i += 16) {
10312
10548
  state = NvmeUpdate16(state, buf.ptr + i);
10313
10549
  }
10314
- for (Size i = right; i < buf.len; i++) {
10550
+ for (Size i = len16; i < buf.len; i++) {
10315
10551
  state = NvmeUpdate1(state, buf[i]);
10316
10552
  }
10317
10553