koffi 2.14.0-beta.3 → 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 (53) hide show
  1. package/CHANGELOG.md +18 -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/input.md +66 -0
  23. package/doc/pages/platforms.md +8 -19
  24. package/doc/pages.ini +0 -7
  25. package/doc/static/perf_windows.png +0 -0
  26. package/index.d.ts +0 -1
  27. package/index.js +10 -9
  28. package/indirect.js +10 -9
  29. package/package.json +3 -2
  30. package/src/cnoke/src/builder.js +1 -2
  31. package/src/core/base/base.cc +815 -554
  32. package/src/core/base/base.hh +578 -450
  33. package/src/core/base/crc.inc +1 -1
  34. package/src/core/base/crc_gen.py +1 -1
  35. package/src/core/base/unicode.inc +1 -1
  36. package/src/core/base/unicode_gen.py +1 -1
  37. package/src/koffi/src/abi_arm32.cc +24 -24
  38. package/src/koffi/src/abi_arm64.cc +29 -29
  39. package/src/koffi/src/abi_riscv64.cc +27 -27
  40. package/src/koffi/src/abi_x64_sysv.cc +29 -29
  41. package/src/koffi/src/abi_x64_win.cc +20 -20
  42. package/src/koffi/src/abi_x86.cc +26 -26
  43. package/src/koffi/src/call.cc +83 -237
  44. package/src/koffi/src/call.hh +8 -8
  45. package/src/koffi/src/ffi.cc +71 -67
  46. package/src/koffi/src/ffi.hh +9 -9
  47. package/src/koffi/src/parser.cc +2 -2
  48. package/src/koffi/src/parser.hh +1 -1
  49. package/src/koffi/src/trampolines/prototypes.inc +1 -1
  50. package/src/koffi/src/util.cc +43 -43
  51. package/src/koffi/src/util.hh +5 -5
  52. package/src/koffi/src/win32.cc +5 -5
  53. 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
@@ -854,14 +854,39 @@ TimeSpec DecomposeTimeLocal(int64_t time)
854
854
  return spec;
855
855
  }
856
856
 
857
+ int64_t ComposeTimeUTC(const TimeSpec &spec)
858
+ {
859
+ K_ASSERT(!spec.offset);
860
+
861
+ struct tm ti = {};
862
+
863
+ ti.tm_year = spec.year - 1900;
864
+ ti.tm_mon = spec.month - 1;
865
+ ti.tm_mday = spec.day;
866
+ ti.tm_hour = spec.hour;
867
+ ti.tm_min = spec.min;
868
+ ti.tm_sec = spec.sec;
869
+
870
+ #if defined(_WIN32)
871
+ int64_t time = (int64_t)_mkgmtime64(&ti);
872
+ #else
873
+ int64_t time = (int64_t)timegm(&ti);
874
+ #endif
875
+
876
+ time *= 1000;
877
+ time += spec.msec;
878
+
879
+ return time;
880
+ }
881
+
857
882
  // ------------------------------------------------------------------------
858
883
  // Strings
859
884
  // ------------------------------------------------------------------------
860
885
 
861
886
  bool CopyString(const char *str, Span<char> buf)
862
887
  {
863
- #if defined(RG_DEBUG)
864
- RG_ASSERT(buf.len > 0);
888
+ #if defined(K_DEBUG)
889
+ K_ASSERT(buf.len > 0);
865
890
  #else
866
891
  if (!buf.len) [[unlikely]]
867
892
  return false;
@@ -882,8 +907,8 @@ bool CopyString(const char *str, Span<char> buf)
882
907
 
883
908
  bool CopyString(Span<const char> str, Span<char> buf)
884
909
  {
885
- #if defined(RG_DEBUG)
886
- RG_ASSERT(buf.len > 0);
910
+ #if defined(K_DEBUG)
911
+ K_ASSERT(buf.len > 0);
887
912
  #else
888
913
  if (!buf.len) [[unlikely]]
889
914
  return false;
@@ -899,7 +924,7 @@ bool CopyString(Span<const char> str, Span<char> buf)
899
924
 
900
925
  Span<char> DuplicateString(Span<const char> str, Allocator *alloc)
901
926
  {
902
- RG_ASSERT(alloc);
927
+ K_ASSERT(alloc);
903
928
 
904
929
  char *new_str = (char *)AllocateRaw(alloc, str.len + 1);
905
930
  MemCpy(new_str, str.ptr, str.len);
@@ -907,23 +932,6 @@ Span<char> DuplicateString(Span<const char> str, Allocator *alloc)
907
932
  return MakeSpan(new_str, str.len);
908
933
  }
909
934
 
910
- bool IsValidUtf8(Span<const char> str)
911
- {
912
- Size i = 0;
913
-
914
- while (i < str.len) {
915
- int32_t uc;
916
- Size bytes = DecodeUtf8(str, i, &uc);
917
-
918
- if (!bytes) [[unlikely]]
919
- return false;
920
-
921
- i += bytes;
922
- }
923
-
924
- return i == str.len;
925
- }
926
-
927
935
  // ------------------------------------------------------------------------
928
936
  // Format
929
937
  // ------------------------------------------------------------------------
@@ -1010,7 +1018,7 @@ static Span<char> FormatUnsignedToSmallHex(uint64_t value, char out_buf[32])
1010
1018
  #if defined(JKJ_HEADER_DRAGONBOX)
1011
1019
  static Size FakeFloatPrecision(Span<char> buf, int K, int min_prec, int max_prec, int *out_K)
1012
1020
  {
1013
- RG_ASSERT(min_prec >= 0);
1021
+ K_ASSERT(min_prec >= 0);
1014
1022
 
1015
1023
  if (-K < min_prec) {
1016
1024
  int delta = min_prec + K;
@@ -1373,7 +1381,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1373
1381
  } break;
1374
1382
 
1375
1383
  case FmtType::Date: {
1376
- RG_ASSERT(!arg.u.date.value || arg.u.date.IsValid());
1384
+ K_ASSERT(!arg.u.date.value || arg.u.date.IsValid());
1377
1385
 
1378
1386
  int year = arg.u.date.st.year;
1379
1387
  if (year < 0) {
@@ -1461,7 +1469,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1461
1469
  static const char *const DefaultChars = "abcdefghijklmnopqrstuvwxyz0123456789";
1462
1470
  Span<const char> chars = arg.u.random.chars ? arg.u.random.chars : DefaultChars;
1463
1471
 
1464
- RG_ASSERT(arg.u.random.len <= RG_SIZE(out_buf.data));
1472
+ K_ASSERT(arg.u.random.len <= K_SIZE(out_buf.data));
1465
1473
 
1466
1474
  for (Size j = 0; j < arg.u.random.len; j++) {
1467
1475
  int rnd = GetRandomInt(0, (int)chars.len);
@@ -1512,9 +1520,9 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1512
1520
  switch (arg.u.span.type) {
1513
1521
  case FmtType::Str1: { arg2.u.str1 = *(const char **)ptr; } break;
1514
1522
  case FmtType::Str2: { arg2.u.str2 = *(const Span<const char> *)ptr; } break;
1515
- case FmtType::Buffer: { RG_UNREACHABLE(); } break;
1523
+ case FmtType::Buffer: { K_UNREACHABLE(); } break;
1516
1524
  case FmtType::Char: { arg2.u.ch = *(const char *)ptr; } break;
1517
- case FmtType::Custom: { RG_UNREACHABLE(); } break;
1525
+ case FmtType::Custom: { K_UNREACHABLE(); } break;
1518
1526
  case FmtType::Bool: { arg2.u.b = *(const bool *)ptr; } break;
1519
1527
  case FmtType::Integer:
1520
1528
  case FmtType::Unsigned:
@@ -1527,7 +1535,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1527
1535
  case 4: { arg2.u.u = *(const uint32_t *)ptr; } break;
1528
1536
  case 2: { arg2.u.u = *(const uint16_t *)ptr; } break;
1529
1537
  case 1: { arg2.u.u = *(const uint8_t *)ptr; } break;
1530
- default: { RG_UNREACHABLE(); } break;
1538
+ default: { K_UNREACHABLE(); } break;
1531
1539
  }
1532
1540
  } break;
1533
1541
  case FmtType::Float: {
@@ -1545,10 +1553,10 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
1545
1553
  case FmtType::Date: { arg2.u.date = *(const LocalDate *)ptr; } break;
1546
1554
  case FmtType::TimeISO:
1547
1555
  case FmtType::TimeNice: { arg2.u.time = *(decltype(FmtArg::u.time) *)ptr; } break;
1548
- case FmtType::Random: { RG_UNREACHABLE(); } break;
1549
- case FmtType::FlagNames: { RG_UNREACHABLE(); } break;
1550
- case FmtType::FlagOptions: { RG_UNREACHABLE(); } break;
1551
- 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;
1552
1560
  }
1553
1561
  ptr += arg.u.span.type_len;
1554
1562
 
@@ -1662,7 +1670,7 @@ static inline Size ProcessAnsiSpecifier(const char *spec, bool vt100, AppendFunc
1662
1670
 
1663
1671
  end:
1664
1672
  if (!valid) {
1665
- #if defined(RG_DEBUG)
1673
+ #if defined(K_DEBUG)
1666
1674
  LogDebug("Format string contains invalid ANSI specifier");
1667
1675
  #endif
1668
1676
  return idx;
@@ -1679,7 +1687,7 @@ end:
1679
1687
  template <typename AppendFunc>
1680
1688
  static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100, AppendFunc append)
1681
1689
  {
1682
- #if defined(RG_DEBUG)
1690
+ #if defined(K_DEBUG)
1683
1691
  bool invalid_marker = false;
1684
1692
  uint32_t unused_arguments = ((uint32_t)1 << args.len) - 1;
1685
1693
  #endif
@@ -1712,7 +1720,7 @@ static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100
1712
1720
  idx--;
1713
1721
  if (idx < args.len) {
1714
1722
  ProcessArg<AppendFunc>(args[idx], append);
1715
- #if defined(RG_DEBUG)
1723
+ #if defined(K_DEBUG)
1716
1724
  unused_arguments &= ~((uint32_t)1 << idx);
1717
1725
  } else {
1718
1726
  invalid_marker = true;
@@ -1723,25 +1731,25 @@ static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100
1723
1731
  append('%');
1724
1732
  fmt_ptr = marker_ptr + 2;
1725
1733
  } else if (marker_ptr[1] == '/') {
1726
- append(*RG_PATH_SEPARATORS);
1734
+ append(*K_PATH_SEPARATORS);
1727
1735
  fmt_ptr = marker_ptr + 2;
1728
1736
  } else if (marker_ptr[1] == '!') {
1729
1737
  fmt_ptr = marker_ptr + 2 + ProcessAnsiSpecifier(marker_ptr + 1, vt100, append);
1730
1738
  } else if (marker_ptr[1]) {
1731
1739
  append(marker_ptr[0]);
1732
1740
  fmt_ptr = marker_ptr + 1;
1733
- #if defined(RG_DEBUG)
1741
+ #if defined(K_DEBUG)
1734
1742
  invalid_marker = true;
1735
1743
  #endif
1736
1744
  } else {
1737
- #if defined(RG_DEBUG)
1745
+ #if defined(K_DEBUG)
1738
1746
  invalid_marker = true;
1739
1747
  #endif
1740
1748
  break;
1741
1749
  }
1742
1750
  }
1743
1751
 
1744
- #if defined(RG_DEBUG)
1752
+ #if defined(K_DEBUG)
1745
1753
  if (invalid_marker && unused_arguments) {
1746
1754
  PrintLn(StdErr, "\nLog format string '%1' has invalid markers and unused arguments", fmt);
1747
1755
  } else if (unused_arguments) {
@@ -1754,7 +1762,7 @@ static inline void DoFormat(const char *fmt, Span<const FmtArg> args, bool vt100
1754
1762
 
1755
1763
  Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, Span<char> out_buf)
1756
1764
  {
1757
- RG_ASSERT(out_buf.len >= 0);
1765
+ K_ASSERT(out_buf.len >= 0);
1758
1766
 
1759
1767
  if (!out_buf.len)
1760
1768
  return {};
@@ -1779,7 +1787,7 @@ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, HeapArra
1779
1787
  {
1780
1788
  Size start_len = out_buf->len;
1781
1789
 
1782
- out_buf->Grow(RG_FMT_STRING_BASE_CAPACITY);
1790
+ out_buf->Grow(K_FMT_STRING_BASE_CAPACITY);
1783
1791
  DoFormat(fmt, args, vt100, [&](Span<const char> frag) {
1784
1792
  out_buf->Grow(frag.len + 1);
1785
1793
  MemCpy(out_buf->end(), frag.ptr, frag.len);
@@ -1792,7 +1800,7 @@ Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, HeapArra
1792
1800
 
1793
1801
  Span<char> FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, Allocator *alloc)
1794
1802
  {
1795
- RG_ASSERT(alloc);
1803
+ K_ASSERT(alloc);
1796
1804
 
1797
1805
  HeapArray<char> buf(alloc);
1798
1806
  FmtFmt(fmt, args, vt100, &buf);
@@ -1808,13 +1816,13 @@ void FmtFmt(const char *fmt, Span<const FmtArg> args, bool vt100, FunctionRef<vo
1808
1816
 
1809
1817
  void PrintFmt(const char *fmt, Span<const FmtArg> args, StreamWriter *st)
1810
1818
  {
1811
- LocalArray<char, RG_FMT_STRING_PRINT_BUFFER_SIZE> buf;
1819
+ LocalArray<char, K_FMT_STRING_PRINT_BUFFER_SIZE> buf;
1812
1820
  DoFormat(fmt, args, st->IsVt100(), [&](Span<const char> frag) {
1813
- if (frag.len > RG_LEN(buf.data) - buf.len) {
1821
+ if (frag.len > K_LEN(buf.data) - buf.len) {
1814
1822
  st->Write(buf);
1815
1823
  buf.len = 0;
1816
1824
  }
1817
- if (frag.len >= RG_LEN(buf.data)) {
1825
+ if (frag.len >= K_LEN(buf.data)) {
1818
1826
  st->Write(frag);
1819
1827
  } else {
1820
1828
  MemCpy(buf.data + buf.len, frag.ptr, frag.len);
@@ -1858,29 +1866,27 @@ void FmtLowerAscii::Format(FunctionRef<void(Span<const char>)> append) const
1858
1866
 
1859
1867
  void FmtEscape::Format(FunctionRef<void(Span<const char>)> append) const
1860
1868
  {
1861
- static const char literals[] = "0123456789ABCDEF";
1862
-
1863
1869
  for (char c: str) {
1864
- if (c >= 32 && (unsigned int)c < 128) {
1865
- 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);
1866
1888
  } else {
1867
- switch (c) {
1868
- case '\t': { append('\t'); } break;
1869
- case '\r': { append("\r"); } break;
1870
- case '\n': { append("\n"); } break;
1871
-
1872
- default: {
1873
- char encoded[4];
1874
-
1875
- encoded[0] = '\\';
1876
- encoded[1] = 'x';
1877
- encoded[2] = literals[((uint8_t)c >> 4) & 0xF];
1878
- encoded[3] = literals[((uint8_t)c >> 0) & 0xF];
1879
-
1880
- Span<const char> buf = MakeSpan(encoded, 4);
1881
- append(buf);
1882
- } break;
1883
- }
1889
+ append(c);
1884
1890
  }
1885
1891
  }
1886
1892
  }
@@ -1907,8 +1913,8 @@ void FmtUrlSafe::Format(FunctionRef<void(Span<const char>)> append) const
1907
1913
 
1908
1914
  FmtArg FmtVersion(int64_t version, int parts, int by)
1909
1915
  {
1910
- RG_ASSERT(version >= 0);
1911
- RG_ASSERT(parts > 0);
1916
+ K_ASSERT(version >= 0);
1917
+ K_ASSERT(parts > 0);
1912
1918
 
1913
1919
  FmtArg arg = {};
1914
1920
  arg.type = FmtType::Buffer;
@@ -1994,7 +2000,7 @@ bool GetDebugFlag(const char *name)
1994
2000
 
1995
2001
  if (debug) {
1996
2002
  bool ret = false;
1997
- if (!ParseBool(debug, &ret, RG_DEFAULT_PARSE_FLAGS & ~(int)ParseFlag::Log)) {
2003
+ if (!ParseBool(debug, &ret, K_DEFAULT_PARSE_FLAGS & ~(int)ParseFlag::Log)) {
1998
2004
  LogError("Environment variable '%1' is not a boolean", name);
1999
2005
  }
2000
2006
  return ret;
@@ -2027,7 +2033,7 @@ void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg>
2027
2033
  if (skip)
2028
2034
  return;
2029
2035
  skip = true;
2030
- RG_DEFER { skip = false; };
2036
+ K_DEFER { skip = false; };
2031
2037
 
2032
2038
  if (!init) {
2033
2039
  // Do this first... GetDebugFlag() might log an error or something, in which
@@ -2047,11 +2053,11 @@ void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg>
2047
2053
 
2048
2054
  char msg_buf[2048];
2049
2055
  {
2050
- Size len = FmtFmt(fmt, args, log_vt100, msg_buf).len;
2056
+ Size len = FmtFmt(T(fmt), args, log_vt100, msg_buf).len;
2051
2057
 
2052
- if (len == RG_SIZE(msg_buf) - 1) {
2053
- strncpy(msg_buf + RG_SIZE(msg_buf) - 32, "... [truncated]", 32);
2054
- 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;
2055
2061
  }
2056
2062
  }
2057
2063
 
@@ -2080,13 +2086,13 @@ void DefaultLogHandler(LogLevel level, const char *ctx, const char *msg)
2080
2086
 
2081
2087
  void PushLogFilter(const std::function<LogFilterFunc> &func)
2082
2088
  {
2083
- RG_ASSERT(log_filters_len < RG_LEN(log_filters));
2089
+ K_ASSERT(log_filters_len < K_LEN(log_filters));
2084
2090
  log_filters[log_filters_len++] = new std::function<LogFilterFunc>(func);
2085
2091
  }
2086
2092
 
2087
2093
  void PopLogFilter()
2088
2094
  {
2089
- RG_ASSERT(log_filters_len > 0);
2095
+ K_ASSERT(log_filters_len > 0);
2090
2096
  delete log_filters[--log_filters_len];
2091
2097
  }
2092
2098
 
@@ -2094,7 +2100,7 @@ void PopLogFilter()
2094
2100
  bool RedirectLogToWindowsEvents(const char *name)
2095
2101
  {
2096
2102
  static HANDLE log = nullptr;
2097
- RG_ASSERT(!log);
2103
+ K_ASSERT(!log);
2098
2104
 
2099
2105
  log = OpenEventLogA(nullptr, name);
2100
2106
  if (!log) {
@@ -2145,7 +2151,7 @@ bool RedirectLogToWindowsEvents(const char *name)
2145
2151
  #if !defined(__wasi__)
2146
2152
 
2147
2153
  struct ProgressState {
2148
- char text[RG_PROGRESS_TEXT_SIZE];
2154
+ char text[K_PROGRESS_TEXT_SIZE];
2149
2155
 
2150
2156
  int64_t value;
2151
2157
  int64_t min;
@@ -2166,7 +2172,7 @@ struct ProgressNode {
2166
2172
  static std::function<ProgressFunc> pg_handler = DefaultProgressHandler;
2167
2173
 
2168
2174
  static std::atomic_int pg_count;
2169
- static ProgressNode pg_nodes[RG_PROGRESS_MAX_NODES];
2175
+ static ProgressNode pg_nodes[K_PROGRESS_MAX_NODES];
2170
2176
 
2171
2177
  static std::mutex pg_mutex;
2172
2178
  static bool pg_run = false;
@@ -2298,22 +2304,22 @@ ProgressNode *ProgressHandle::AcquireNode()
2298
2304
 
2299
2305
  pg_run = true;
2300
2306
  }
2301
- } else if (count > RG_PROGRESS_USED_NODES) {
2307
+ } else if (count > K_PROGRESS_USED_NODES) {
2302
2308
  pg_count--;
2303
2309
  return nullptr;
2304
2310
  }
2305
2311
 
2306
- int base = GetRandomInt(0, RG_LEN(pg_nodes));
2312
+ int base = GetRandomInt(0, K_LEN(pg_nodes));
2307
2313
 
2308
- for (int i = 0; i < RG_LEN(pg_nodes); i++) {
2309
- 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);
2310
2316
 
2311
2317
  ProgressNode *node = &pg_nodes[idx];
2312
2318
  bool used = node->used.exchange(true);
2313
2319
 
2314
2320
  if (!used) {
2315
- static_assert(RG_SIZE(text) == RG_SIZE(node->front.text));
2316
- 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));
2317
2323
 
2318
2324
  ProgressNode *prev = nullptr;
2319
2325
  bool set = this->node.compare_exchange_strong(prev, node);
@@ -2332,16 +2338,16 @@ ProgressNode *ProgressHandle::AcquireNode()
2332
2338
  return nullptr;
2333
2339
  }
2334
2340
 
2335
- 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])
2336
2342
  {
2337
- Span<char> buf = MakeSpan(out, RG_PROGRESS_TEXT_SIZE);
2343
+ Span<char> buf = MakeSpan(out, K_PROGRESS_TEXT_SIZE);
2338
2344
  bool complete = CopyString(text, buf);
2339
2345
 
2340
2346
  if (!complete) [[unlikely]] {
2341
- out[RG_PROGRESS_TEXT_SIZE - 4] = '.';
2342
- out[RG_PROGRESS_TEXT_SIZE - 3] = '.';
2343
- out[RG_PROGRESS_TEXT_SIZE - 2] = '.';
2344
- 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;
2345
2351
  }
2346
2352
  }
2347
2353
 
@@ -2466,8 +2472,8 @@ Size ConvertWin32WideToUtf8(LPCWSTR str_w, Span<char> out_str)
2466
2472
  int len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, out_str.ptr, (int)out_str.len - 1, nullptr, nullptr);
2467
2473
  if (!len) {
2468
2474
  switch (GetLastError()) {
2469
- case ERROR_INSUFFICIENT_BUFFER: { LogError("String '<UTF-16 ?>' is too large"); } break;
2470
- 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;
2471
2477
  default: { LogError("WideCharToMultiByte() failed: %1", GetWin32ErrorString()); } break;
2472
2478
  }
2473
2479
  return -1;
@@ -2487,16 +2493,16 @@ char *GetWin32ErrorString(uint32_t error_code)
2487
2493
  if (win32_utf8) {
2488
2494
  if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
2489
2495
  nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2490
- str_buf, RG_SIZE(str_buf), nullptr))
2496
+ str_buf, K_SIZE(str_buf), nullptr))
2491
2497
  goto fail;
2492
2498
  } else {
2493
2499
  wchar_t buf_w[256];
2494
2500
  if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
2495
2501
  nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2496
- buf_w, RG_SIZE(buf_w), nullptr))
2502
+ buf_w, K_SIZE(buf_w), nullptr))
2497
2503
  goto fail;
2498
2504
 
2499
- 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))
2500
2506
  goto fail;
2501
2507
  }
2502
2508
 
@@ -2586,7 +2592,7 @@ StatResult StatFile(int fd, const char *filename, unsigned int flags, FileInfo *
2586
2592
  } break;
2587
2593
  }
2588
2594
  }
2589
- RG_DEFER { CloseHandle(h); };
2595
+ K_DEFER { CloseHandle(h); };
2590
2596
 
2591
2597
  return StatHandle(h, filename, out_info);
2592
2598
  } else {
@@ -2597,7 +2603,7 @@ StatResult StatFile(int fd, const char *filename, unsigned int flags, FileInfo *
2597
2603
 
2598
2604
  RenameResult RenameFile(const char *src_filename, const char *dest_filename, unsigned int silent, unsigned int flags)
2599
2605
  {
2600
- RG_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
2606
+ K_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
2601
2607
 
2602
2608
  DWORD move_flags = (flags & (int)RenameFlag::Overwrite) ? MOVEFILE_REPLACE_EXISTING : 0;
2603
2609
  DWORD err = ERROR_SUCCESS;
@@ -2630,11 +2636,11 @@ RenameResult RenameFile(const char *src_filename, const char *dest_filename, uns
2630
2636
 
2631
2637
  if (err == ERROR_ALREADY_EXISTS) {
2632
2638
  if (!(silent & (int)RenameResult::AlreadyExists)) {
2633
- 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);
2634
2640
  }
2635
2641
  return RenameResult::AlreadyExists;
2636
2642
  } else {
2637
- 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));
2638
2644
  return RenameResult::OtherError;
2639
2645
  }
2640
2646
  }
@@ -2648,7 +2654,7 @@ bool ResizeFile(int fd, const char *filename, int64_t len)
2648
2654
  LogError("Failed to resize file '%1': %2", filename, GetWin32ErrorString());
2649
2655
  return false;
2650
2656
  }
2651
- RG_DEFER { SetFilePointerEx(h, prev_pos, nullptr, FILE_BEGIN); };
2657
+ K_DEFER { SetFilePointerEx(h, prev_pos, nullptr, FILE_BEGIN); };
2652
2658
 
2653
2659
  if (!SetFilePointerEx(h, { .QuadPart = len }, nullptr, FILE_BEGIN)) {
2654
2660
  LogError("Failed to resize file '%1': %2", filename, GetWin32ErrorString());
@@ -2719,7 +2725,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2719
2725
  FunctionRef<bool(const char *, const FileInfo &)> func)
2720
2726
  {
2721
2727
  if (filter) {
2722
- RG_ASSERT(!strpbrk(filter, RG_PATH_SEPARATORS));
2728
+ K_ASSERT(!strpbrk(filter, K_PATH_SEPARATORS));
2723
2729
  } else {
2724
2730
  filter = "*";
2725
2731
  }
@@ -2727,7 +2733,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2727
2733
  wchar_t find_filter_w[4096];
2728
2734
  {
2729
2735
  char find_filter[4096];
2730
- 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)) {
2731
2737
  LogError("Cannot enumerate directory '%1': Path too long", dirname);
2732
2738
  return EnumResult::OtherError;
2733
2739
  }
@@ -2764,7 +2770,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
2764
2770
  default: return EnumResult::OtherError;
2765
2771
  }
2766
2772
  }
2767
- RG_DEFER { FindClose(handle); };
2773
+ K_DEFER { FindClose(handle); };
2768
2774
 
2769
2775
  Size count = 0;
2770
2776
  do {
@@ -2984,19 +2990,19 @@ StatResult StatFile(int fd, const char *path, unsigned int flags, FileInfo *out_
2984
2990
  static bool SyncDirectory(Span<const char> directory)
2985
2991
  {
2986
2992
  char directory0[4096];
2987
- if (directory.len >= RG_SIZE(directory0)) {
2993
+ if (directory.len >= K_SIZE(directory0)) {
2988
2994
  LogError("Failed to sync directory '%1': path too long", directory);
2989
2995
  return false;
2990
2996
  }
2991
2997
  MemCpy(directory0, directory.ptr, directory.len);
2992
2998
  directory0[directory.len] = 0;
2993
2999
 
2994
- 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);
2995
3001
  if (dirfd < 0) {
2996
3002
  LogError("Failed to sync directory '%1': %2", directory, strerror(errno));
2997
3003
  return false;
2998
3004
  }
2999
- RG_DEFER { CloseDescriptor(dirfd); };
3005
+ K_DEFER { CloseDescriptor(dirfd); };
3000
3006
 
3001
3007
  if (fsync(dirfd) < 0) {
3002
3008
  LogError("Failed to sync directory '%1': %2", directory, strerror(errno));
@@ -3014,7 +3020,7 @@ static inline bool IsErrnoNotSupported(int err)
3014
3020
 
3015
3021
  RenameResult RenameFile(const char *src_filename, const char *dest_filename, unsigned int silent, unsigned int flags)
3016
3022
  {
3017
- RG_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
3023
+ K_ASSERT(!(silent & ((int)RenameResult::Success | (int)RenameResult::OtherError)));
3018
3024
 
3019
3025
  if (flags & (int)RenameFlag::Overwrite) {
3020
3026
  if (rename(src_filename, dest_filename) < 0)
@@ -3121,7 +3127,7 @@ bool SetFileMetaData(int fd, const char *filename, int64_t mtime, int64_t, uint3
3121
3127
  times[1].tv_nsec = (mtime % 1000) * 1000000;
3122
3128
 
3123
3129
  if (futimens(fd, times) < 0) {
3124
- LogError("Failed to set mtime of '%1'", filename);
3130
+ LogError("Failed to set modification time of '%1': %2", filename, filename);
3125
3131
  valid = false;
3126
3132
  }
3127
3133
  if (fchmod(fd, (mode_t)mode) < 0) {
@@ -3255,7 +3261,7 @@ static EnumResult ReadDirectory(DIR *dirp, const char *dirname, const char *filt
3255
3261
  EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_files,
3256
3262
  FunctionRef<bool(const char *, FileType)> func)
3257
3263
  {
3258
- DIR *dirp = RG_RESTART_EINTR(opendir(dirname), == nullptr);
3264
+ DIR *dirp = K_RESTART_EINTR(opendir(dirname), == nullptr);
3259
3265
  if (!dirp) {
3260
3266
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3261
3267
 
@@ -3265,7 +3271,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
3265
3271
  default: return EnumResult::OtherError;
3266
3272
  }
3267
3273
  }
3268
- RG_DEFER { closedir(dirp); };
3274
+ K_DEFER { closedir(dirp); };
3269
3275
 
3270
3276
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3271
3277
  }
@@ -3273,7 +3279,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
3273
3279
  EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_files,
3274
3280
  FunctionRef<bool(const char *, const FileInfo &)> func)
3275
3281
  {
3276
- DIR *dirp = RG_RESTART_EINTR(opendir(dirname), == nullptr);
3282
+ DIR *dirp = K_RESTART_EINTR(opendir(dirname), == nullptr);
3277
3283
  if (!dirp) {
3278
3284
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3279
3285
 
@@ -3283,7 +3289,7 @@ EnumResult EnumerateDirectory(const char *dirname, const char *filter, Size max_
3283
3289
  default: return EnumResult::OtherError;
3284
3290
  }
3285
3291
  }
3286
- RG_DEFER { closedir(dirp); };
3292
+ K_DEFER { closedir(dirp); };
3287
3293
 
3288
3294
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3289
3295
  }
@@ -3300,7 +3306,7 @@ EnumResult EnumerateDirectory(int fd, const char *dirname, const char *filter, S
3300
3306
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3301
3307
  return EnumResult::OtherError;
3302
3308
  }
3303
- RG_DEFER { closedir(dirp); };
3309
+ K_DEFER { closedir(dirp); };
3304
3310
 
3305
3311
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3306
3312
  }
@@ -3315,7 +3321,7 @@ EnumResult EnumerateDirectory(int fd, const char *dirname, const char *filter, S
3315
3321
  LogError("Cannot enumerate directory '%1': %2", dirname, strerror(errno));
3316
3322
  return EnumResult::OtherError;
3317
3323
  }
3318
- RG_DEFER { closedir(dirp); };
3324
+ K_DEFER { closedir(dirp); };
3319
3325
 
3320
3326
  return ReadDirectory(dirp, dirname, filter, max_files, func);
3321
3327
  }
@@ -3327,7 +3333,7 @@ EnumResult EnumerateDirectory(int fd, const char *dirname, const char *filter, S
3327
3333
  bool EnumerateFiles(const char *dirname, const char *filter, Size max_depth, Size max_files,
3328
3334
  Allocator *str_alloc, HeapArray<const char *> *out_files)
3329
3335
  {
3330
- 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); };
3331
3337
 
3332
3338
  EnumResult ret = EnumerateDirectory(dirname, nullptr, max_files,
3333
3339
  [&](const char *basename, FileType file_type) {
@@ -3398,7 +3404,7 @@ bool TestFile(const char *filename, FileType type)
3398
3404
  case FileType::Pipe: { LogError("Path '%1' is not a pipe", filename); } break;
3399
3405
  case FileType::Socket: { LogError("Path '%1' is not a socket", filename); } break;
3400
3406
 
3401
- case FileType::Link: { RG_UNREACHABLE(); } break;
3407
+ case FileType::Link: { K_UNREACHABLE(); } break;
3402
3408
  }
3403
3409
 
3404
3410
  return false;
@@ -3536,7 +3542,7 @@ bool MatchPathSpec(const char *path, const char *spec, bool case_sensitive)
3536
3542
  Span<const char> path2 = path;
3537
3543
 
3538
3544
  do {
3539
- const char *it = SplitStrReverseAny(path2, RG_PATH_SEPARATORS, &path2).ptr;
3545
+ const char *it = SplitStrReverseAny(path2, K_PATH_SEPARATORS, &path2).ptr;
3540
3546
 
3541
3547
  if (MatchPathName(it, spec, case_sensitive))
3542
3548
  return true;
@@ -3547,10 +3553,10 @@ bool MatchPathSpec(const char *path, const char *spec, bool case_sensitive)
3547
3553
 
3548
3554
  bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *alloc, const char **out_path)
3549
3555
  {
3550
- RG_ASSERT(alloc || !out_path);
3556
+ K_ASSERT(alloc || !out_path);
3551
3557
 
3552
3558
  // Fast path
3553
- if (strpbrk(name, RG_PATH_SEPARATORS)) {
3559
+ if (strpbrk(name, K_PATH_SEPARATORS)) {
3554
3560
  if (!TestFile(name, FileType::File))
3555
3561
  return false;
3556
3562
 
@@ -3561,7 +3567,7 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
3561
3567
  }
3562
3568
 
3563
3569
  while (paths.len) {
3564
- Span<const char> path = SplitStr(paths, RG_PATH_DELIMITER, &paths);
3570
+ Span<const char> path = SplitStr(paths, K_PATH_DELIMITER, &paths);
3565
3571
 
3566
3572
  LocalArray<char, 4096> buf;
3567
3573
  buf.len = Fmt(buf.data, "%1%/%2", path, name).len;
@@ -3582,7 +3588,7 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
3582
3588
  }
3583
3589
  }
3584
3590
  #else
3585
- if (buf.len < RG_SIZE(buf.data) - 1 && TestFile(buf.data)) {
3591
+ if (buf.len < K_SIZE(buf.data) - 1 && TestFile(buf.data)) {
3586
3592
  if (out_path) {
3587
3593
  *out_path = DuplicateString(buf.data, alloc).ptr;
3588
3594
  }
@@ -3596,10 +3602,10 @@ bool FindExecutableInPath(Span<const char> paths, const char *name, Allocator *a
3596
3602
 
3597
3603
  bool FindExecutableInPath(const char *name, Allocator *alloc, const char **out_path)
3598
3604
  {
3599
- RG_ASSERT(alloc || !out_path);
3605
+ K_ASSERT(alloc || !out_path);
3600
3606
 
3601
3607
  // Fast path
3602
- if (strpbrk(name, RG_PATH_SEPARATORS)) {
3608
+ if (strpbrk(name, K_PATH_SEPARATORS)) {
3603
3609
  if (!TestFile(name, FileType::File))
3604
3610
  return false;
3605
3611
 
@@ -3615,13 +3621,13 @@ bool FindExecutableInPath(const char *name, Allocator *alloc, const char **out_p
3615
3621
  if (win32_utf8) {
3616
3622
  paths = GetEnv("PATH");
3617
3623
  } else {
3618
- wchar_t buf_w[RG_SIZE(env_buf.data)];
3619
- 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));
3620
3626
 
3621
3627
  if (!len && GetLastError() != ERROR_ENVVAR_NOT_FOUND) {
3622
3628
  LogError("Failed to get PATH environment variable: %1", GetWin32ErrorString());
3623
3629
  return false;
3624
- } else if (len >= RG_LEN(buf_w)) {
3630
+ } else if (len >= K_LEN(buf_w)) {
3625
3631
  LogError("Failed to get PATH environment variable: buffer to small");
3626
3632
  return false;
3627
3633
  }
@@ -3671,19 +3677,19 @@ const char *GetWorkingDirectory()
3671
3677
 
3672
3678
  #if defined(_WIN32)
3673
3679
  if (!win32_utf8) {
3674
- wchar_t buf_w[RG_SIZE(buf)];
3675
- DWORD ret = GetCurrentDirectoryW(RG_SIZE(buf_w), buf_w);
3676
- 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));
3677
3683
 
3678
3684
  Size str_len = ConvertWin32WideToUtf8(buf_w, buf);
3679
- RG_ASSERT(str_len >= 0);
3685
+ K_ASSERT(str_len >= 0);
3680
3686
 
3681
3687
  return buf;
3682
3688
  }
3683
3689
  #endif
3684
3690
 
3685
- const char *ptr = getcwd(buf, RG_SIZE(buf));
3686
- RG_ASSERT(ptr);
3691
+ const char *ptr = getcwd(buf, K_SIZE(buf));
3692
+ K_ASSERT(ptr);
3687
3693
 
3688
3694
  return buf;
3689
3695
  }
@@ -3695,15 +3701,15 @@ const char *GetApplicationExecutable()
3695
3701
 
3696
3702
  if (!executable_path[0]) {
3697
3703
  if (win32_utf8) {
3698
- Size path_len = (Size)GetModuleFileNameA(nullptr, executable_path, RG_SIZE(executable_path));
3699
- 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));
3700
3706
  } else {
3701
- wchar_t path_w[RG_SIZE(executable_path)];
3702
- Size path_len = (Size)GetModuleFileNameW(nullptr, path_w, RG_SIZE(path_w));
3703
- 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));
3704
3710
 
3705
3711
  Size str_len = ConvertWin32WideToUtf8(path_w, executable_path);
3706
- RG_ASSERT(str_len >= 0);
3712
+ K_ASSERT(str_len >= 0);
3707
3713
  }
3708
3714
  }
3709
3715
 
@@ -3712,13 +3718,13 @@ const char *GetApplicationExecutable()
3712
3718
  static char executable_path[4096];
3713
3719
 
3714
3720
  if (!executable_path[0]) {
3715
- uint32_t buffer_size = RG_SIZE(executable_path);
3721
+ uint32_t buffer_size = K_SIZE(executable_path);
3716
3722
  int ret = _NSGetExecutablePath(executable_path, &buffer_size);
3717
- RG_ASSERT(!ret);
3723
+ K_ASSERT(!ret);
3718
3724
 
3719
3725
  char *path_buf = realpath(executable_path, nullptr);
3720
- RG_ASSERT(path_buf);
3721
- RG_ASSERT(strlen(path_buf) < RG_SIZE(executable_path));
3726
+ K_ASSERT(path_buf);
3727
+ K_ASSERT(strlen(path_buf) < K_SIZE(executable_path));
3722
3728
 
3723
3729
  CopyString(path_buf, executable_path);
3724
3730
  free(path_buf);
@@ -3729,8 +3735,8 @@ const char *GetApplicationExecutable()
3729
3735
  static char executable_path[4096];
3730
3736
 
3731
3737
  if (!executable_path[0]) {
3732
- ssize_t ret = readlink("/proc/self/exe", executable_path, RG_SIZE(executable_path));
3733
- 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));
3734
3740
  }
3735
3741
 
3736
3742
  return executable_path;
@@ -3742,27 +3748,27 @@ const char *GetApplicationExecutable()
3742
3748
 
3743
3749
  size_t argc;
3744
3750
  {
3745
- int ret = sysctl(name, RG_LEN(name), nullptr, &argc, NULL, 0);
3746
- RG_ASSERT(ret >= 0);
3747
- 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);
3748
3754
  }
3749
3755
 
3750
3756
  HeapArray<char *> argv;
3751
3757
  {
3752
3758
  argv.AppendDefault(argc);
3753
- int ret = sysctl(name, RG_LEN(name), argv.ptr, &argc, nullptr, 0);
3754
- RG_ASSERT(ret >= 0);
3759
+ int ret = sysctl(name, K_LEN(name), argv.ptr, &argc, nullptr, 0);
3760
+ K_ASSERT(ret >= 0);
3755
3761
  }
3756
3762
 
3757
3763
  if (PathIsAbsolute(argv[0])) {
3758
- RG_ASSERT(strlen(argv[0]) < RG_SIZE(executable_path));
3764
+ K_ASSERT(strlen(argv[0]) < K_SIZE(executable_path));
3759
3765
 
3760
3766
  CopyString(argv[0], executable_path);
3761
3767
  } else {
3762
3768
  const char *path;
3763
3769
  bool success = FindExecutableInPath(argv[0], GetDefaultAllocator(), &path);
3764
- RG_ASSERT(success);
3765
- RG_ASSERT(strlen(path) < RG_SIZE(executable_path));
3770
+ K_ASSERT(success);
3771
+ K_ASSERT(strlen(path) < K_SIZE(executable_path));
3766
3772
 
3767
3773
  CopyString(path, executable_path);
3768
3774
  ReleaseRaw(nullptr, (void *)path, -1);
@@ -3777,9 +3783,9 @@ const char *GetApplicationExecutable()
3777
3783
  int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
3778
3784
  size_t len = sizeof(executable_path);
3779
3785
 
3780
- int ret = sysctl(name, RG_LEN(name), executable_path, &len, NULL, 0);
3781
- RG_ASSERT(ret >= 0);
3782
- 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));
3783
3789
  }
3784
3790
 
3785
3791
  return executable_path;
@@ -3808,7 +3814,7 @@ const char *GetApplicationDirectory()
3808
3814
  Span<const char> GetPathDirectory(Span<const char> filename)
3809
3815
  {
3810
3816
  Span<const char> directory;
3811
- SplitStrReverseAny(filename, RG_PATH_SEPARATORS, &directory);
3817
+ SplitStrReverseAny(filename, K_PATH_SEPARATORS, &directory);
3812
3818
 
3813
3819
  return directory.len ? directory : ".";
3814
3820
  }
@@ -3816,7 +3822,7 @@ Span<const char> GetPathDirectory(Span<const char> filename)
3816
3822
  // Names starting with a dot are not considered to be an extension (POSIX hidden files)
3817
3823
  Span<const char> GetPathExtension(Span<const char> filename, CompressionType *out_compression_type)
3818
3824
  {
3819
- filename = SplitStrReverseAny(filename, RG_PATH_SEPARATORS);
3825
+ filename = SplitStrReverseAny(filename, K_PATH_SEPARATORS);
3820
3826
 
3821
3827
  Span<const char> extension = {};
3822
3828
  const auto consume_next_extension = [&]() {
@@ -3855,7 +3861,7 @@ CompressionType GetPathCompression(Span<const char> filename)
3855
3861
 
3856
3862
  Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, unsigned int flags, Allocator *alloc)
3857
3863
  {
3858
- RG_ASSERT(alloc);
3864
+ K_ASSERT(alloc);
3859
3865
 
3860
3866
  if (!path.len && !root_directory.len)
3861
3867
  return Fmt(alloc, "");
@@ -3863,17 +3869,17 @@ Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory,
3863
3869
  HeapArray<char> buf(alloc);
3864
3870
  Size parts_count = 0;
3865
3871
 
3866
- char separator = (flags & (int)NormalizeFlag::ForceSlash) ? '/' : *RG_PATH_SEPARATORS;
3872
+ char separator = (flags & (int)NormalizeFlag::ForceSlash) ? '/' : *K_PATH_SEPARATORS;
3867
3873
 
3868
3874
  const auto append_normalized_path = [&](Span<const char> path) {
3869
3875
  if (!buf.len && PathIsAbsolute(path)) {
3870
- Span<const char> prefix = SplitStrAny(path, RG_PATH_SEPARATORS, &path);
3876
+ Span<const char> prefix = SplitStrAny(path, K_PATH_SEPARATORS, &path);
3871
3877
  buf.Append(prefix);
3872
3878
  buf.Append(separator);
3873
3879
  }
3874
3880
 
3875
3881
  while (path.len) {
3876
- Span<const char> part = SplitStrAny(path, RG_PATH_SEPARATORS, &path);
3882
+ Span<const char> part = SplitStrAny(path, K_PATH_SEPARATORS, &path);
3877
3883
 
3878
3884
  if (part == "..") {
3879
3885
  if (parts_count) {
@@ -3957,15 +3963,16 @@ bool PathContainsDotDot(const char *path)
3957
3963
 
3958
3964
  static bool CheckForDumbTerm()
3959
3965
  {
3960
- static bool init = false;
3961
- static bool dumb = false;
3962
-
3963
- if (!init) {
3966
+ static bool dumb = ([]() {
3964
3967
  const char *term = GetEnv("TERM");
3965
3968
 
3966
- dumb |= term && TestStr(term, "dumb");
3967
- dumb |= !!GetEnv("NO_COLOR");
3968
- }
3969
+ if (term && TestStr(term, "dumb"))
3970
+ return true;
3971
+ if (GetEnv("NO_COLOR"))
3972
+ return true;
3973
+
3974
+ return false;
3975
+ })();
3969
3976
 
3970
3977
  return dumb;
3971
3978
  }
@@ -3974,7 +3981,7 @@ static bool CheckForDumbTerm()
3974
3981
 
3975
3982
  OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silent, int *out_fd)
3976
3983
  {
3977
- RG_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
3984
+ K_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
3978
3985
 
3979
3986
  DWORD access = 0;
3980
3987
  DWORD share = 0;
@@ -4013,7 +4020,7 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4013
4020
  oflags = _O_WRONLY | _O_CREAT | _O_APPEND | _O_BINARY | _O_NOINHERIT;
4014
4021
  } break;
4015
4022
  }
4016
- RG_ASSERT(oflags >= 0);
4023
+ K_ASSERT(oflags >= 0);
4017
4024
 
4018
4025
  if (flags & (int)OpenFlag::Keep) {
4019
4026
  if (creation == CREATE_ALWAYS) {
@@ -4022,20 +4029,20 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4022
4029
  oflags &= ~_O_TRUNC;
4023
4030
  }
4024
4031
  if (flags & (int)OpenFlag::Directory) {
4025
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4026
- RG_ASSERT(!(flags & (int)OpenFlag::Append));
4032
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4033
+ K_ASSERT(!(flags & (int)OpenFlag::Append));
4027
4034
 
4028
4035
  creation = OPEN_EXISTING;
4029
4036
  attributes = FILE_FLAG_BACKUP_SEMANTICS;
4030
4037
  oflags &= ~(_O_CREAT | _O_TRUNC | _O_BINARY);
4031
4038
  }
4032
4039
  if (flags & (int)OpenFlag::Exists) {
4033
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4040
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4034
4041
 
4035
4042
  creation = OPEN_EXISTING;
4036
4043
  oflags &= ~_O_CREAT;
4037
4044
  } else if (flags & (int)OpenFlag::Exclusive) {
4038
- RG_ASSERT(creation == CREATE_ALWAYS);
4045
+ K_ASSERT(creation == CREATE_ALWAYS);
4039
4046
 
4040
4047
  creation = CREATE_NEW;
4041
4048
  oflags |= (int)_O_EXCL;
@@ -4043,7 +4050,7 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4043
4050
 
4044
4051
  HANDLE h = nullptr;
4045
4052
  int fd = -1;
4046
- RG_DEFER_N(err_guard) {
4053
+ K_DEFER_N(err_guard) {
4047
4054
  CloseDescriptor(fd);
4048
4055
  if (h) {
4049
4056
  CloseHandle(h);
@@ -4104,7 +4111,7 @@ void CloseDescriptor(int fd)
4104
4111
 
4105
4112
  bool FlushFile(int fd, const char *filename)
4106
4113
  {
4107
- RG_ASSERT(filename);
4114
+ K_ASSERT(filename);
4108
4115
 
4109
4116
  HANDLE h = (HANDLE)_get_osfhandle(fd);
4110
4117
 
@@ -4152,7 +4159,7 @@ bool SpliceFile(int src_fd, const char *src_filename, int64_t src_offset,
4152
4159
  (RtlNtStatusToDosErrorFunc *)(void *)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlNtStatusToDosError");
4153
4160
 
4154
4161
  unsigned long err = RtlNtStatusToDosError(status);
4155
- 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));
4156
4163
 
4157
4164
  return false;
4158
4165
  }
@@ -4184,7 +4191,7 @@ bool SpliceFile(int src_fd, const char *src_filename, int64_t src_offset,
4184
4191
 
4185
4192
  while (size) {
4186
4193
  LocalArray<uint8_t, 655536> buf;
4187
- 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));
4188
4195
 
4189
4196
  buf.len = _read(src_fd, buf.data, count);
4190
4197
 
@@ -4226,7 +4233,7 @@ bool SpliceFile(int src_fd, const char *src_filename, int64_t src_offset,
4226
4233
  return true;
4227
4234
  }
4228
4235
 
4229
- RG_UNREACHABLE();
4236
+ K_UNREACHABLE();
4230
4237
  }
4231
4238
 
4232
4239
  bool FileIsVt100(int fd)
@@ -4266,11 +4273,6 @@ bool FileIsVt100(int fd)
4266
4273
  }
4267
4274
  }
4268
4275
 
4269
- if (emulation && win32_utf8) {
4270
- SetConsoleCP(CP_UTF8); // Does not work yet, but it might some day
4271
- SetConsoleOutputCP(CP_UTF8);
4272
- }
4273
-
4274
4276
  return emulation;
4275
4277
  }();
4276
4278
 
@@ -4416,7 +4418,7 @@ error:
4416
4418
 
4417
4419
  OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silent, int *out_fd)
4418
4420
  {
4419
- RG_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
4421
+ K_ASSERT(!(silent & ((int)OpenResult::Success | (int)OpenResult::OtherError)));
4420
4422
 
4421
4423
  int oflags = -1;
4422
4424
  switch (flags & ((int)OpenFlag::Read |
@@ -4427,29 +4429,29 @@ OpenResult OpenFile(const char *filename, unsigned int flags, unsigned int silen
4427
4429
  case (int)OpenFlag::Read | (int)OpenFlag::Write: { oflags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC; } break;
4428
4430
  case (int)OpenFlag::Append: { oflags = O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC; } break;
4429
4431
  }
4430
- RG_ASSERT(oflags >= 0);
4432
+ K_ASSERT(oflags >= 0);
4431
4433
 
4432
4434
  if (flags & (int)OpenFlag::Keep) {
4433
4435
  oflags &= ~O_TRUNC;
4434
4436
  }
4435
4437
  if (flags & (int)OpenFlag::Directory) {
4436
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4437
- RG_ASSERT(!(flags & (int)OpenFlag::Append));
4438
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4439
+ K_ASSERT(!(flags & (int)OpenFlag::Append));
4438
4440
 
4439
4441
  oflags &= ~(O_CREAT | O_WRONLY | O_RDWR | O_TRUNC);
4440
4442
  }
4441
4443
  if (flags & (int)OpenFlag::Exists) {
4442
- RG_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4444
+ K_ASSERT(!(flags & (int)OpenFlag::Exclusive));
4443
4445
  oflags &= ~O_CREAT;
4444
4446
  } else if (flags & (int)OpenFlag::Exclusive) {
4445
- RG_ASSERT(oflags & O_CREAT);
4447
+ K_ASSERT(oflags & O_CREAT);
4446
4448
  oflags |= O_EXCL;
4447
4449
  }
4448
4450
  if (flags & (int)OpenFlag::NoFollow) {
4449
4451
  oflags |= O_NOFOLLOW;
4450
4452
  }
4451
4453
 
4452
- int fd = RG_RESTART_EINTR(open(filename, oflags, 0644), < 0);
4454
+ int fd = K_RESTART_EINTR(open(filename, oflags, 0644), < 0);
4453
4455
  if (fd < 0) {
4454
4456
  OpenResult ret;
4455
4457
  switch (errno) {
@@ -4481,7 +4483,7 @@ void CloseDescriptor(int fd)
4481
4483
 
4482
4484
  bool FlushFile(int fd, const char *filename)
4483
4485
  {
4484
- RG_ASSERT(filename);
4486
+ K_ASSERT(filename);
4485
4487
 
4486
4488
  #if defined(__APPLE__)
4487
4489
  if (fsync(fd) < 0 && errno != EINVAL && errno != ENOTSUP) {
@@ -4614,7 +4616,7 @@ unsupported:
4614
4616
 
4615
4617
  while (size) {
4616
4618
  LocalArray<uint8_t, 655536> buf;
4617
- 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));
4618
4620
 
4619
4621
  buf.len = read(src_fd, buf.data, (size_t)count);
4620
4622
 
@@ -4656,7 +4658,7 @@ unsupported:
4656
4658
  return true;
4657
4659
  }
4658
4660
 
4659
- RG_UNREACHABLE();
4661
+ K_UNREACHABLE();
4660
4662
  }
4661
4663
 
4662
4664
  bool FileIsVt100(int fd)
@@ -4710,7 +4712,7 @@ bool MakeDirectory(const char *directory, bool error_if_exists)
4710
4712
  bool MakeDirectoryRec(Span<const char> directory)
4711
4713
  {
4712
4714
  char buf[4096];
4713
- if (directory.len >= RG_SIZE(buf)) [[unlikely]] {
4715
+ if (directory.len >= K_SIZE(buf)) [[unlikely]] {
4714
4716
  LogError("Path '%1' is too large", directory);
4715
4717
  return false;
4716
4718
  }
@@ -4736,7 +4738,7 @@ bool MakeDirectoryRec(Span<const char> directory)
4736
4738
  return false;
4737
4739
  }
4738
4740
 
4739
- buf[offset] = *RG_PATH_SEPARATORS;
4741
+ buf[offset] = *K_PATH_SEPARATORS;
4740
4742
  }
4741
4743
  }
4742
4744
 
@@ -4802,7 +4804,7 @@ bool CreateOverlappedPipe(bool overlap0, bool overlap1, PipeMode mode, HANDLE ou
4802
4804
  static LONG pipe_idx;
4803
4805
 
4804
4806
  HANDLE handles[2] = {};
4805
- RG_DEFER_N(handle_guard) {
4807
+ K_DEFER_N(handle_guard) {
4806
4808
  CloseHandleSafe(&handles[0]);
4807
4809
  CloseHandleSafe(&handles[1]);
4808
4810
  };
@@ -4914,14 +4916,14 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4914
4916
  LogError("Failed to create job object: %1", GetWin32ErrorString());
4915
4917
  return false;
4916
4918
  }
4917
- RG_DEFER { CloseHandleSafe(&job_handle); };
4919
+ K_DEFER { CloseHandleSafe(&job_handle); };
4918
4920
 
4919
4921
  // If I die, everyone dies!
4920
4922
  {
4921
4923
  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limits = {};
4922
4924
  limits.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
4923
4925
 
4924
- if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &limits, RG_SIZE(limits))) {
4926
+ if (!SetInformationJobObject(job_handle, JobObjectExtendedLimitInformation, &limits, K_SIZE(limits))) {
4925
4927
  LogError("SetInformationJobObject() failed: %1", GetWin32ErrorString());
4926
4928
  return false;
4927
4929
  }
@@ -4929,7 +4931,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4929
4931
 
4930
4932
  // Create read pipes
4931
4933
  HANDLE in_pipe[2] = {};
4932
- RG_DEFER {
4934
+ K_DEFER {
4933
4935
  CloseHandleSafe(&in_pipe[0]);
4934
4936
  CloseHandleSafe(&in_pipe[1]);
4935
4937
  };
@@ -4938,7 +4940,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4938
4940
 
4939
4941
  // Create write pipes
4940
4942
  HANDLE out_pipe[2] = {};
4941
- RG_DEFER {
4943
+ K_DEFER {
4942
4944
  CloseHandleSafe(&out_pipe[0]);
4943
4945
  CloseHandleSafe(&out_pipe[1]);
4944
4946
  };
@@ -4987,7 +4989,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4987
4989
  // Start process
4988
4990
  HANDLE process_handle;
4989
4991
  {
4990
- RG_DEFER {
4992
+ K_DEFER {
4991
4993
  CloseHandleSafe(&si.hStdInput);
4992
4994
  CloseHandleSafe(&si.hStdOutput);
4993
4995
  CloseHandleSafe(&si.hStdError);
@@ -5027,7 +5029,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5027
5029
  CloseHandleSafe(&in_pipe[0]);
5028
5030
  CloseHandleSafe(&out_pipe[1]);
5029
5031
  }
5030
- RG_DEFER { CloseHandleSafe(&process_handle); };
5032
+ K_DEFER { CloseHandleSafe(&process_handle); };
5031
5033
 
5032
5034
  // Read and write standard process streams
5033
5035
  {
@@ -5049,11 +5051,11 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5049
5051
 
5050
5052
  if (!write_buf.len) {
5051
5053
  write_buf = in_func();
5052
- RG_ASSERT(write_buf.len >= 0);
5054
+ K_ASSERT(write_buf.len >= 0);
5053
5055
  }
5054
5056
 
5055
5057
  if (write_buf.len) {
5056
- RG_ASSERT(write_buf.len < UINT_MAX);
5058
+ K_ASSERT(write_buf.len < UINT_MAX);
5057
5059
 
5058
5060
  if (!WriteFileEx(in_pipe[1], write_buf.ptr, (DWORD)write_buf.len,
5059
5061
  &proc_in.ov, PendingIO::CompletionHandler)) {
@@ -5079,7 +5081,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5079
5081
  proc_out.len = -1;
5080
5082
  }
5081
5083
 
5082
- 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)) {
5083
5085
  proc_out.err = GetLastError();
5084
5086
  }
5085
5087
  }
@@ -5109,7 +5111,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5109
5111
  console_ctrl_event
5110
5112
  };
5111
5113
 
5112
- if (WaitForMultipleObjects(RG_LEN(events), events, FALSE, INFINITE) == WAIT_FAILED) {
5114
+ if (WaitForMultipleObjects(K_LEN(events), events, FALSE, INFINITE) == WAIT_FAILED) {
5113
5115
  LogError("WaitForMultipleObjects() failed: %1", GetWin32ErrorString());
5114
5116
  return false;
5115
5117
  }
@@ -5164,11 +5166,11 @@ static void DefaultSignalHandler(int signal)
5164
5166
  #endif
5165
5167
 
5166
5168
  pid_t pid = getpid();
5167
- RG_ASSERT(pid > 1);
5169
+ K_ASSERT(pid > 1);
5168
5170
 
5169
5171
  if (interrupt_pfd[1] >= 0) {
5170
5172
  char dummy = 0;
5171
- RG_IGNORE write(interrupt_pfd[1], &dummy, 1);
5173
+ K_IGNORE write(interrupt_pfd[1], &dummy, 1);
5172
5174
  }
5173
5175
 
5174
5176
  if (flag_signal) {
@@ -5224,7 +5226,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5224
5226
 
5225
5227
  // Create read pipes
5226
5228
  int in_pfd[2] = {-1, -1};
5227
- RG_DEFER {
5229
+ K_DEFER {
5228
5230
  CloseDescriptorSafe(&in_pfd[0]);
5229
5231
  CloseDescriptorSafe(&in_pfd[1]);
5230
5232
  };
@@ -5239,7 +5241,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5239
5241
 
5240
5242
  // Create write pipes
5241
5243
  int out_pfd[2] = {-1, -1};
5242
- RG_DEFER {
5244
+ K_DEFER {
5243
5245
  CloseDescriptorSafe(&out_pfd[0]);
5244
5246
  CloseDescriptorSafe(&out_pfd[1]);
5245
5247
  };
@@ -5300,7 +5302,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5300
5302
  LogError("Failed to set up standard process descriptors: %1", strerror(errno));
5301
5303
  return false;
5302
5304
  }
5303
- RG_DEFER { posix_spawn_file_actions_destroy(&file_actions); };
5305
+ K_DEFER { posix_spawn_file_actions_destroy(&file_actions); };
5304
5306
 
5305
5307
  if (in_func.IsValid() && (errno = posix_spawn_file_actions_adddup2(&file_actions, in_pfd[0], STDIN_FILENO))) {
5306
5308
  LogError("Failed to set up standard process descriptors: %1", strerror(errno));
@@ -5348,7 +5350,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5348
5350
  pfds.Append({ interrupt_pfd[0], POLLIN, 0 });
5349
5351
  }
5350
5352
 
5351
- 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) {
5352
5354
  LogError("Failed to poll process I/O: %1", strerror(errno));
5353
5355
  break;
5354
5356
  }
@@ -5361,15 +5363,15 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5361
5363
  if (in_revents & (POLLHUP | POLLERR)) {
5362
5364
  CloseDescriptorSafe(&in_pfd[1]);
5363
5365
  } else if (in_revents & POLLOUT) {
5364
- RG_ASSERT(in_func.IsValid());
5366
+ K_ASSERT(in_func.IsValid());
5365
5367
 
5366
5368
  if (!write_buf.len) {
5367
5369
  write_buf = in_func();
5368
- RG_ASSERT(write_buf.len >= 0);
5370
+ K_ASSERT(write_buf.len >= 0);
5369
5371
  }
5370
5372
 
5371
5373
  if (write_buf.len) {
5372
- 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);
5373
5375
 
5374
5376
  if (write_len > 0) {
5375
5377
  write_buf.ptr += write_len;
@@ -5389,10 +5391,10 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5389
5391
  if (out_revents & POLLERR) {
5390
5392
  break;
5391
5393
  } else if (out_revents & (POLLIN | POLLHUP)) {
5392
- RG_ASSERT(out_func.IsValid());
5394
+ K_ASSERT(out_func.IsValid());
5393
5395
 
5394
5396
  uint8_t read_buf[4096];
5395
- 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);
5396
5398
 
5397
5399
  if (read_len > 0) {
5398
5400
  out_func(MakeSpan(read_buf, read_len));
@@ -5423,7 +5425,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5423
5425
  int64_t start = GetMonotonicTime();
5424
5426
 
5425
5427
  for (;;) {
5426
- 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);
5427
5429
 
5428
5430
  if (ret < 0) {
5429
5431
  LogError("Failed to wait for process exit: %1", strerror(errno));
@@ -5461,18 +5463,18 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
5461
5463
  HeapArray<uint8_t> *out_buf, int *out_code)
5462
5464
  {
5463
5465
  Size start_len = out_buf->len;
5464
- RG_DEFER_N(out_guard) { out_buf->RemoveFrom(start_len); };
5466
+ K_DEFER_N(out_guard) { out_buf->RemoveFrom(start_len); };
5465
5467
 
5466
5468
  // Check virtual memory limits
5467
5469
  {
5468
- Size memory_max = RG_SIZE_MAX - out_buf->len - 1;
5470
+ Size memory_max = K_SIZE_MAX - out_buf->len - 1;
5469
5471
 
5470
5472
  if (memory_max <= 0) [[unlikely]] {
5471
5473
  LogError("Exhausted memory limit");
5472
5474
  return false;
5473
5475
  }
5474
5476
 
5475
- RG_ASSERT(max_len);
5477
+ K_ASSERT(max_len);
5476
5478
  max_len = (max_len >= 0) ? std::min(max_len, memory_max) : memory_max;
5477
5479
  }
5478
5480
 
@@ -5553,8 +5555,8 @@ static HANDLE wait_msg_event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
5553
5555
 
5554
5556
  void WaitDelay(int64_t delay)
5555
5557
  {
5556
- RG_ASSERT(delay >= 0);
5557
- RG_ASSERT(delay < 1000ll * INT32_MAX);
5558
+ K_ASSERT(delay >= 0);
5559
+ K_ASSERT(delay < 1000ll * INT32_MAX);
5558
5560
 
5559
5561
  while (delay) {
5560
5562
  DWORD delay32 = (DWORD)std::min(delay, (int64_t)UINT32_MAX);
@@ -5564,15 +5566,31 @@ void WaitDelay(int64_t delay)
5564
5566
  }
5565
5567
  }
5566
5568
 
5567
- WaitForResult WaitForInterrupt(int64_t timeout)
5569
+ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready)
5568
5570
  {
5571
+ K_ASSERT(sources.len <= 62);
5572
+
5569
5573
  ignore_ctrl_event = InitConsoleCtrlHandler();
5570
- RG_ASSERT(ignore_ctrl_event);
5574
+ K_ASSERT(ignore_ctrl_event);
5571
5575
 
5572
- HANDLE events[] = {
5573
- console_ctrl_event,
5574
- wait_msg_event
5575
- };
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
+ }
5576
5594
 
5577
5595
  DWORD ret;
5578
5596
  if (timeout >= 0) {
@@ -5580,26 +5598,50 @@ WaitForResult WaitForInterrupt(int64_t timeout)
5580
5598
  DWORD timeout32 = (DWORD)std::min(timeout, (int64_t)UINT32_MAX);
5581
5599
  timeout -= timeout32;
5582
5600
 
5583
- ret = WaitForMultipleObjects(RG_LEN(events), events, FALSE, timeout32);
5601
+ ret = MsgWaitForMultipleObjects((DWORD)events.len, events.data, FALSE, timeout32, wake);
5584
5602
  } while (ret == WAIT_TIMEOUT && timeout);
5585
5603
  } else {
5586
- ret = WaitForMultipleObjects(RG_LEN(events), events, FALSE, INFINITE);
5604
+ ret = MsgWaitForMultipleObjects((DWORD)events.len, events.data, FALSE, INFINITE, wake);
5587
5605
  }
5588
5606
 
5589
5607
  switch (ret) {
5590
- case WAIT_OBJECT_0: return WaitForResult::Interrupt;
5608
+ case WAIT_OBJECT_0: return WaitResult::Interrupt;
5591
5609
  case WAIT_OBJECT_0 + 1: {
5592
5610
  ResetEvent(wait_msg_event);
5593
- return WaitForResult::Message;
5611
+ return WaitResult::Message;
5594
5612
  } break;
5595
5613
  default: {
5596
- RG_ASSERT(ret == WAIT_TIMEOUT);
5597
- 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;
5598
5633
  } break;
5634
+ case WAIT_TIMEOUT: return WaitResult::Timeout;
5599
5635
  }
5600
5636
  }
5601
5637
 
5602
- void SignalWaitFor()
5638
+ WaitResult WaitEvents(int64_t timeout)
5639
+ {
5640
+ Span<const WaitSource> sources = {};
5641
+ return WaitEvents(sources, timeout);
5642
+ }
5643
+
5644
+ void InterruptWait()
5603
5645
  {
5604
5646
  SetEvent(wait_msg_event);
5605
5647
  }
@@ -5608,8 +5650,8 @@ void SignalWaitFor()
5608
5650
 
5609
5651
  void WaitDelay(int64_t delay)
5610
5652
  {
5611
- RG_ASSERT(delay >= 0);
5612
- RG_ASSERT(delay < 1000ll * INT32_MAX);
5653
+ K_ASSERT(delay >= 0);
5654
+ K_ASSERT(delay < 1000ll * INT32_MAX);
5613
5655
 
5614
5656
  struct timespec ts;
5615
5657
  ts.tv_sec = (int)(delay / 1000);
@@ -5617,49 +5659,79 @@ void WaitDelay(int64_t delay)
5617
5659
 
5618
5660
  struct timespec rem;
5619
5661
  while (nanosleep(&ts, &rem) < 0) {
5620
- RG_ASSERT(errno == EINTR);
5662
+ K_ASSERT(errno == EINTR);
5621
5663
  ts = rem;
5622
5664
  }
5623
5665
  }
5624
5666
 
5625
5667
  #if !defined(__wasi__)
5626
5668
 
5627
- WaitForResult WaitForInterrupt(int64_t timeout)
5669
+ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready)
5628
5670
  {
5671
+ LocalArray<struct pollfd, 64> pfds;
5672
+ K_ASSERT(sources.len <= K_LEN(pfds.data));
5673
+
5629
5674
  static std::atomic_bool message { false };
5630
5675
 
5631
5676
  flag_signal = true;
5632
5677
  SetSignalHandler(SIGUSR1, [](int) { message = true; });
5633
5678
 
5634
- if (timeout >= 0) {
5635
- struct timespec ts;
5636
- ts.tv_sec = (int)(timeout / 1000);
5637
- 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
+ }
5638
5683
 
5639
- struct timespec rem;
5640
- while (!explicit_signal && !message && nanosleep(&ts, &rem) < 0) {
5641
- RG_ASSERT(errno == EINTR);
5642
- 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;
5643
5696
  }
5644
- } else {
5645
- while (!explicit_signal && !message) {
5646
- 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;
5647
5715
  }
5648
- }
5649
5716
 
5650
- if (explicit_signal == SIGTERM) {
5651
- return WaitForResult::Exit;
5652
- } else if (explicit_signal) {
5653
- return WaitForResult::Interrupt;
5654
- } else if (message) {
5655
- message = false;
5656
- return WaitForResult::Message;
5657
- } else {
5658
- 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
+ }
5659
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);
5660
5732
  }
5661
5733
 
5662
- void SignalWaitFor()
5734
+ void InterruptWait()
5663
5735
  {
5664
5736
  pid_t pid = getpid();
5665
5737
  kill(pid, SIGUSR1);
@@ -5693,7 +5765,7 @@ int GetCoreCount()
5693
5765
  cores = (int)std::thread::hardware_concurrency();
5694
5766
  }
5695
5767
 
5696
- RG_ASSERT(cores > 0);
5768
+ K_ASSERT(cores > 0);
5697
5769
  }
5698
5770
 
5699
5771
  return cores;
@@ -5719,7 +5791,7 @@ bool RaiseMaximumOpenFiles(int limit)
5719
5791
  lim.rlim_cur = std::min(target, lim.rlim_max);
5720
5792
 
5721
5793
  if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
5722
- LogError("Could not raise RLIMIT_NOFILE: %2", strerror(errno));
5794
+ LogError("Could not raise RLIMIT_NOFILE: %1", strerror(errno));
5723
5795
  return false;
5724
5796
  }
5725
5797
 
@@ -5750,7 +5822,7 @@ bool DropRootIdentity()
5750
5822
  goto error;
5751
5823
  if (setreuid(uid, uid) < 0)
5752
5824
  goto error;
5753
- RG_CRITICAL(setuid(0) < 0, "Managed to regain root privileges");
5825
+ K_CRITICAL(setuid(0) < 0, "Managed to regain root privileges");
5754
5826
 
5755
5827
  return true;
5756
5828
 
@@ -5780,7 +5852,7 @@ bool NotifySystemd()
5780
5852
 
5781
5853
  addr.sun_family = AF_UNIX;
5782
5854
  addr.sun_path[0] = 0;
5783
- 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));
5784
5856
  } else if (addr_str[0] == '/') {
5785
5857
  if (strlen(addr_str) >= sizeof(addr.sun_path)) {
5786
5858
  LogError("Socket pathname in NOTIFY_SOCKET is too long");
@@ -5799,7 +5871,7 @@ bool NotifySystemd()
5799
5871
  LogError("Failed to create UNIX socket: %1", strerror(errno));
5800
5872
  return false;
5801
5873
  }
5802
- RG_DEFER { close(fd); };
5874
+ K_DEFER { close(fd); };
5803
5875
 
5804
5876
  struct iovec iov = {};
5805
5877
  struct msghdr msg = {};
@@ -5825,6 +5897,23 @@ bool NotifySystemd()
5825
5897
  // Main
5826
5898
  // ------------------------------------------------------------------------
5827
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
+
5828
5917
  void InitApp()
5829
5918
  {
5830
5919
  #if defined(_WIN32)
@@ -5832,6 +5921,9 @@ void InitApp()
5832
5921
  _setmode(STDIN_FILENO, _O_BINARY);
5833
5922
  _setmode(STDOUT_FILENO, _O_BINARY);
5834
5923
  _setmode(STDERR_FILENO, _O_BINARY);
5924
+
5925
+ SetConsoleCP(CP_UTF8);
5926
+ SetConsoleOutputCP(CP_UTF8);
5835
5927
  #endif
5836
5928
 
5837
5929
  #if !defined(_WIN32) && !defined(__wasi__)
@@ -5848,12 +5940,16 @@ void InitApp()
5848
5940
  atexit([]() {
5849
5941
  if (interrupt_pfd[1] >= 0) {
5850
5942
  pid_t pid = getpid();
5851
- RG_ASSERT(pid > 1);
5943
+ K_ASSERT(pid > 1);
5852
5944
 
5853
5945
  SetSignalHandler(SIGTERM, [](int) {});
5854
5946
  kill(-pid, SIGTERM);
5855
5947
  }
5856
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();
5857
5953
  #endif
5858
5954
 
5859
5955
  #if defined(__OpenBSD__)
@@ -5861,6 +5957,28 @@ void InitApp()
5861
5957
  // so we want to cache the result as soon as possible.
5862
5958
  GetApplicationExecutable();
5863
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
+ }
5864
5982
  }
5865
5983
 
5866
5984
  // ------------------------------------------------------------------------
@@ -5871,18 +5989,18 @@ void InitApp()
5871
5989
 
5872
5990
  const char *GetUserConfigPath(const char *name, Allocator *alloc)
5873
5991
  {
5874
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
5992
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5875
5993
 
5876
5994
  static char cache_dir[4096];
5877
5995
  static std::once_flag flag;
5878
5996
 
5879
5997
  std::call_once(flag, []() {
5880
5998
  wchar_t *dir = nullptr;
5881
- RG_DEFER { CoTaskMemFree(dir); };
5999
+ K_DEFER { CoTaskMemFree(dir); };
5882
6000
 
5883
- RG_CRITICAL(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &dir) == S_OK,
6001
+ K_CRITICAL(SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, nullptr, &dir) == S_OK,
5884
6002
  "Failed to retrieve path to roaming user AppData");
5885
- RG_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
6003
+ K_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
5886
6004
  "Path to roaming AppData is invalid or too big");
5887
6005
  });
5888
6006
 
@@ -5892,18 +6010,18 @@ const char *GetUserConfigPath(const char *name, Allocator *alloc)
5892
6010
 
5893
6011
  const char *GetUserCachePath(const char *name, Allocator *alloc)
5894
6012
  {
5895
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6013
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5896
6014
 
5897
6015
  static char cache_dir[4096];
5898
6016
  static std::once_flag flag;
5899
6017
 
5900
6018
  std::call_once(flag, []() {
5901
6019
  wchar_t *dir = nullptr;
5902
- RG_DEFER { CoTaskMemFree(dir); };
6020
+ K_DEFER { CoTaskMemFree(dir); };
5903
6021
 
5904
- RG_CRITICAL(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &dir) == S_OK,
6022
+ K_CRITICAL(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &dir) == S_OK,
5905
6023
  "Failed to retrieve path to local user AppData");
5906
- RG_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
6024
+ K_CRITICAL(ConvertWin32WideToUtf8(dir, cache_dir) >= 0,
5907
6025
  "Path to local AppData is invalid or too big");
5908
6026
  });
5909
6027
 
@@ -5919,16 +6037,16 @@ const char *GetTemporaryDirectory()
5919
6037
  std::call_once(flag, []() {
5920
6038
  Size len;
5921
6039
  if (win32_utf8) {
5922
- len = (Size)GetTempPathA(RG_SIZE(temp_dir), temp_dir);
5923
- 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");
5924
6042
  } else {
5925
6043
  static wchar_t dir_w[4096];
5926
- Size len_w = (Size)GetTempPathW(RG_LEN(dir_w), dir_w);
6044
+ Size len_w = (Size)GetTempPathW(K_LEN(dir_w), dir_w);
5927
6045
 
5928
- 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");
5929
6047
 
5930
6048
  len = ConvertWin32WideToUtf8(dir_w, temp_dir);
5931
- 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");
5932
6050
  }
5933
6051
 
5934
6052
  while (len > 0 && IsPathSeparator(temp_dir[len - 1])) {
@@ -5944,7 +6062,7 @@ const char *GetTemporaryDirectory()
5944
6062
 
5945
6063
  const char *GetUserConfigPath(const char *name, Allocator *alloc)
5946
6064
  {
5947
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6065
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5948
6066
 
5949
6067
  const char *xdg = GetEnv("XDG_CONFIG_HOME");
5950
6068
  const char *home = GetEnv("HOME");
@@ -5969,7 +6087,7 @@ const char *GetUserConfigPath(const char *name, Allocator *alloc)
5969
6087
 
5970
6088
  const char *GetUserCachePath(const char *name, Allocator *alloc)
5971
6089
  {
5972
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6090
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5973
6091
 
5974
6092
  const char *xdg = GetEnv("XDG_CACHE_HOME");
5975
6093
  const char *home = GetEnv("HOME");
@@ -5994,7 +6112,7 @@ const char *GetUserCachePath(const char *name, Allocator *alloc)
5994
6112
 
5995
6113
  const char *GetSystemConfigPath(const char *name, Allocator *alloc)
5996
6114
  {
5997
- RG_ASSERT(!strchr(RG_PATH_SEPARATORS, name[0]));
6115
+ K_ASSERT(!strchr(K_PATH_SEPARATORS, name[0]));
5998
6116
 
5999
6117
  const char *path = Fmt(alloc, "/etc/%1", name).ptr;
6000
6118
  return path;
@@ -6012,7 +6130,7 @@ const char *GetTemporaryDirectory()
6012
6130
  env.len--;
6013
6131
  }
6014
6132
 
6015
- if (env.len && env.len < RG_SIZE(temp_dir)) {
6133
+ if (env.len && env.len < K_SIZE(temp_dir)) {
6016
6134
  CopyString(env, temp_dir);
6017
6135
  } else {
6018
6136
  CopyString("/tmp", temp_dir);
@@ -6027,7 +6145,7 @@ const char *GetTemporaryDirectory()
6027
6145
  const char *FindConfigFile(const char *directory, Span<const char *const> names,
6028
6146
  Allocator *alloc, HeapArray<const char *> *out_possibilities)
6029
6147
  {
6030
- RG_ASSERT(!directory || directory[0]);
6148
+ K_ASSERT(!directory || directory[0]);
6031
6149
 
6032
6150
  decltype(GetUserConfigPath) *funcs[] = {
6033
6151
  GetUserConfigPath,
@@ -6053,7 +6171,7 @@ const char *FindConfigFile(const char *directory, Span<const char *const> names,
6053
6171
 
6054
6172
  LocalArray<const char *, 8> tests;
6055
6173
  {
6056
- RG_ASSERT(names.len <= tests.Available());
6174
+ K_ASSERT(names.len <= tests.Available());
6057
6175
 
6058
6176
  for (const char *name: names) {
6059
6177
  if (directory) {
@@ -6088,11 +6206,11 @@ const char *FindConfigFile(const char *directory, Span<const char *const> names,
6088
6206
  static const char *CreateUniquePath(Span<const char> directory, const char *prefix, const char *extension,
6089
6207
  Allocator *alloc, FunctionRef<bool(const char *path)> create)
6090
6208
  {
6091
- RG_ASSERT(alloc);
6209
+ K_ASSERT(alloc);
6092
6210
 
6093
6211
  HeapArray<char> filename(alloc);
6094
6212
  filename.Append(directory);
6095
- filename.Append(*RG_PATH_SEPARATORS);
6213
+ filename.Append(*K_PATH_SEPARATORS);
6096
6214
  if (prefix) {
6097
6215
  filename.Append(prefix);
6098
6216
  filename.Append('.');
@@ -6101,7 +6219,7 @@ static const char *CreateUniquePath(Span<const char> directory, const char *pref
6101
6219
  Size change_offset = filename.len;
6102
6220
 
6103
6221
  PushLogFilter([](LogLevel, const char *, const char *, FunctionRef<LogFunc>) {});
6104
- RG_DEFER_N(log_guard) { PopLogFilter(); };
6222
+ K_DEFER_N(log_guard) { PopLogFilter(); };
6105
6223
 
6106
6224
  for (Size i = 0; i < 1000; i++) {
6107
6225
  // We want to show an error on last try
@@ -6166,9 +6284,9 @@ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags, Span<c
6166
6284
  bool value = false;
6167
6285
 
6168
6286
  switch (str.len) {
6169
- default: { RG_ASSERT(str.len >= 0); } [[fallthrough]];
6287
+ default: { K_ASSERT(str.len >= 0); } [[fallthrough]];
6170
6288
 
6171
- #if defined(RG_BIG_ENDIAN)
6289
+ #if defined(K_BIG_ENDIAN)
6172
6290
  case 8: { u.raw[0] = LowerAscii(str[7]); } [[fallthrough]];
6173
6291
  case 7: { u.raw[1] = LowerAscii(str[6]); } [[fallthrough]];
6174
6292
  case 6: { u.raw[2] = LowerAscii(str[5]); } [[fallthrough]];
@@ -6421,7 +6539,7 @@ malformed:
6421
6539
  bool ParseVersion(Span<const char> str, int parts, int multiplier,
6422
6540
  int64_t *out_version, unsigned int flags, Span<const char> *out_remaining)
6423
6541
  {
6424
- RG_ASSERT(parts >= 0 && parts < 6);
6542
+ K_ASSERT(parts >= 0 && parts < 6);
6425
6543
 
6426
6544
  int64_t version = 0;
6427
6545
  Span<const char> remain = str;
@@ -6488,35 +6606,42 @@ static inline uint64_t ROTL64(uint64_t v, int n)
6488
6606
  return (v << n) | (v >> (64 - n));
6489
6607
  }
6490
6608
 
6491
- 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)
6492
6610
  {
6493
- alignas(uint32_t) static char str[] = "expand 32-byte k";
6494
- 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
+ }
6495
6616
 
6496
- state[0] = LittleEndian(magic[0]);
6497
- state[1] = LittleEndian(magic[1]);
6498
- state[2] = LittleEndian(magic[2]);
6499
- state[3] = LittleEndian(magic[3]);
6500
- state[4] = LittleEndian(key[0]);
6501
- state[5] = LittleEndian(key[1]);
6502
- state[6] = LittleEndian(key[2]);
6503
- state[7] = LittleEndian(key[3]);
6504
- state[8] = LittleEndian(key[4]);
6505
- state[9] = LittleEndian(key[5]);
6506
- state[10] = LittleEndian(key[6]);
6507
- state[11] = LittleEndian(key[7]);
6508
- state[12] = 0;
6509
- state[13] = 0;
6510
- state[14] = LittleEndian(iv[0]);
6511
- state[15] = LittleEndian(iv[1]);
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";
6620
+
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);
6512
6637
  }
6513
6638
 
6514
- static void RunChaCha20(uint32_t state[16], uint8_t out_buf[64])
6639
+ void RunChaCha20(uint32_t state[16], uint8_t out_buf[64])
6515
6640
  {
6516
6641
  uint32_t *out_buf32 = (uint32_t *)out_buf;
6517
6642
 
6518
6643
  uint32_t x[16];
6519
- MemCpy(x, state, RG_SIZE(x));
6644
+ MemCpy(x, state, K_SIZE(x));
6520
6645
 
6521
6646
  for (Size i = 0; i < 20; i += 2) {
6522
6647
  x[0] += x[4]; x[12] = ROTL32(x[12] ^ x[0], 16);
@@ -6560,7 +6685,7 @@ static void RunChaCha20(uint32_t state[16], uint8_t out_buf[64])
6560
6685
  x[9] += x[14]; x[4] = ROTL32(x[4] ^ x[9], 7);
6561
6686
  }
6562
6687
 
6563
- for (Size i = 0; i < RG_LEN(x); i++) {
6688
+ for (Size i = 0; i < K_LEN(x); i++) {
6564
6689
  out_buf32[i] = LittleEndian(x[i] + state[i]);
6565
6690
  }
6566
6691
 
@@ -6580,26 +6705,26 @@ void FillRandomSafe(void *out_buf, Size len)
6580
6705
  #endif
6581
6706
 
6582
6707
  if (reseed) {
6583
- struct { uint32_t key[8]; uint32_t iv[2]; } buf;
6708
+ struct { uint8_t key[32]; uint8_t iv[8]; } buf;
6584
6709
 
6585
- MemSet(rnd_state, 0, RG_SIZE(rnd_state));
6710
+ MemSet(rnd_state, 0, K_SIZE(rnd_state));
6586
6711
  #if defined(_WIN32)
6587
- RG_CRITICAL(RtlGenRandom(&buf, RG_SIZE(buf)), "RtlGenRandom() failed: %1", GetWin32ErrorString());
6712
+ K_CRITICAL(RtlGenRandom(&buf, K_SIZE(buf)), "RtlGenRandom() failed: %1", GetWin32ErrorString());
6588
6713
  #elif defined(__linux__)
6589
6714
  {
6590
6715
  restart:
6591
- int ret = syscall(SYS_getrandom, &buf, RG_SIZE(buf), 0);
6592
- 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));
6593
6718
 
6594
- if (ret < RG_SIZE(buf)) [[unlikely]]
6719
+ if (ret < K_SIZE(buf)) [[unlikely]]
6595
6720
  goto restart;
6596
6721
  }
6597
6722
  #else
6598
- 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));
6599
6724
  #endif
6600
6725
 
6601
6726
  InitChaCha20(rnd_state, buf.key, buf.iv);
6602
- ZeroSafe(&buf, RG_SIZE(buf));
6727
+ ZeroSafe(&buf, K_SIZE(buf));
6603
6728
 
6604
6729
  rnd_remain = Mebibytes(4);
6605
6730
  rnd_time = GetMonotonicTime();
@@ -6607,18 +6732,18 @@ restart:
6607
6732
  rnd_pid = getpid();
6608
6733
  #endif
6609
6734
 
6610
- rnd_offset = RG_SIZE(rnd_buf);
6735
+ rnd_offset = K_SIZE(rnd_buf);
6611
6736
  }
6612
6737
 
6613
- 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);
6614
6739
  MemCpy(out_buf, rnd_buf + rnd_offset, copy_len);
6615
6740
  ZeroSafe(rnd_buf + rnd_offset, copy_len);
6616
6741
  rnd_offset += copy_len;
6617
6742
 
6618
- 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)) {
6619
6744
  RunChaCha20(rnd_state, rnd_buf);
6620
6745
 
6621
- copy_len = std::min(RG_SIZE(rnd_buf), len - i);
6746
+ copy_len = std::min(K_SIZE(rnd_buf), len - i);
6622
6747
  MemCpy((uint8_t *)out_buf + i, rnd_buf, copy_len);
6623
6748
  ZeroSafe(rnd_buf, copy_len);
6624
6749
  rnd_offset = copy_len;
@@ -6630,7 +6755,7 @@ restart:
6630
6755
  FastRandom::FastRandom()
6631
6756
  {
6632
6757
  do {
6633
- FillRandomSafe(state, RG_SIZE(state));
6758
+ FillRandomSafe(state, K_SIZE(state));
6634
6759
  } while (std::all_of(std::begin(state), std::end(state), [](uint64_t v) { return !v; }));
6635
6760
  }
6636
6761
 
@@ -6647,12 +6772,30 @@ FastRandom::FastRandom(uint64_t seed)
6647
6772
  }
6648
6773
  }
6649
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
+
6650
6793
  void FastRandom::Fill(void *out_buf, Size len)
6651
6794
  {
6652
6795
  for (Size i = 0; i < len; i += 8) {
6653
6796
  uint64_t rnd = Next();
6654
6797
 
6655
- Size copy_len = std::min(RG_SIZE(rnd), len - i);
6798
+ Size copy_len = std::min(K_SIZE(rnd), len - i);
6656
6799
  MemCpy((uint8_t *)out_buf + i, &rnd, copy_len);
6657
6800
  }
6658
6801
  }
@@ -6662,7 +6805,7 @@ int FastRandom::GetInt(int min, int max)
6662
6805
  int range = max - min;
6663
6806
 
6664
6807
  if (range < 2) [[unlikely]] {
6665
- RG_ASSERT(range >= 1);
6808
+ K_ASSERT(range >= 1);
6666
6809
  return min;
6667
6810
  }
6668
6811
 
@@ -6682,7 +6825,7 @@ int64_t FastRandom::GetInt64(int64_t min, int64_t max)
6682
6825
  int64_t range = max - min;
6683
6826
 
6684
6827
  if (range < 2) [[unlikely]] {
6685
- RG_ASSERT(range >= 1);
6828
+ K_ASSERT(range >= 1);
6686
6829
  return min;
6687
6830
  }
6688
6831
 
@@ -6697,22 +6840,9 @@ int64_t FastRandom::GetInt64(int64_t min, int64_t max)
6697
6840
  return min + (int64_t)x;
6698
6841
  }
6699
6842
 
6700
- uint64_t FastRandom::Next()
6843
+ uint64_t GetRandom()
6701
6844
  {
6702
- // xoshiro256++ by David Blackman and Sebastiano Vigna (vigna@acm.org)
6703
- // Hopefully I did not screw it up :)
6704
-
6705
- uint64_t result = ROTL64(state[0] + state[3], 23) + state[0];
6706
- uint64_t t = state[1] << 17;
6707
-
6708
- state[2] ^= state[0];
6709
- state[3] ^= state[1];
6710
- state[1] ^= state[2];
6711
- state[0] ^= state[3];
6712
- state[2] ^= t;
6713
- state[3] = ROTL64(state[3], 45);
6714
-
6715
- return result;
6845
+ return rng_fast.Next();
6716
6846
  }
6717
6847
 
6718
6848
  int GetRandomInt(int min, int max)
@@ -6749,7 +6879,7 @@ bool InitWinsock()
6749
6879
  return;
6750
6880
  }
6751
6881
 
6752
- RG_ASSERT(LOBYTE(wsa.wVersion) == 2 && HIBYTE(wsa.wVersion) == 2);
6882
+ K_ASSERT(LOBYTE(wsa.wVersion) == 2 && HIBYTE(wsa.wVersion) == 2);
6753
6883
  atexit([]() { WSACleanup(); });
6754
6884
 
6755
6885
  ready = true;
@@ -6780,7 +6910,7 @@ int CreateSocket(SocketType type, int flags)
6780
6910
  LogError("Failed to create IP socket: %1", GetWin32ErrorString());
6781
6911
  return -1;
6782
6912
  }
6783
- RG_DEFER_N(err_guard) { closesocket(sock); };
6913
+ K_DEFER_N(err_guard) { closesocket(sock); };
6784
6914
 
6785
6915
  int reuse = 1;
6786
6916
  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
@@ -6817,10 +6947,10 @@ int CreateSocket(SocketType type, int flags)
6817
6947
 
6818
6948
  int sock = socket(family, flags, 0);
6819
6949
  if (sock < 0) {
6820
- LogError("Failed to create AF_INET socket: %1", strerror(errno));
6950
+ LogError("Failed to create IP socket: %1", strerror(errno));
6821
6951
  return -1;
6822
6952
  }
6823
- RG_DEFER_N(err_guard) { close(sock); };
6953
+ K_DEFER_N(err_guard) { close(sock); };
6824
6954
 
6825
6955
  #if !defined(SOCK_CLOEXEC)
6826
6956
  fcntl(sock, F_SETFD, FD_CLOEXEC);
@@ -6853,7 +6983,7 @@ int CreateSocket(SocketType type, int flags)
6853
6983
 
6854
6984
  bool BindIPSocket(int sock, SocketType type, int port)
6855
6985
  {
6856
- RG_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
6986
+ K_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
6857
6987
 
6858
6988
  if (type == SocketType::IPv4) {
6859
6989
  struct sockaddr_in addr = {};
@@ -6919,12 +7049,12 @@ bool BindUnixSocket(int sock, const char *path)
6919
7049
 
6920
7050
  int OpenIPSocket(SocketType type, int port, int flags)
6921
7051
  {
6922
- RG_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
7052
+ K_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
6923
7053
 
6924
7054
  int sock = CreateSocket(type, flags);
6925
7055
  if (sock < 0)
6926
7056
  return -1;
6927
- RG_DEFER_N(err_guard) { CloseSocket(sock); };
7057
+ K_DEFER_N(err_guard) { CloseSocket(sock); };
6928
7058
 
6929
7059
  if (!BindIPSocket(sock, type, port))
6930
7060
  return -1;
@@ -6938,7 +7068,7 @@ int OpenUnixSocket(const char *path, int flags)
6938
7068
  int sock = CreateSocket(SocketType::Unix, flags);
6939
7069
  if (sock < 0)
6940
7070
  return -1;
6941
- RG_DEFER_N(err_guard) { CloseSocket(sock); };
7071
+ K_DEFER_N(err_guard) { CloseSocket(sock); };
6942
7072
 
6943
7073
  if (!BindUnixSocket(sock, path))
6944
7074
  return -1;
@@ -6960,7 +7090,7 @@ int ConnectToUnixSocket(const char *path, int flags)
6960
7090
  int sock = CreateSocket(SocketType::Unix, flags);
6961
7091
  if (sock < 0)
6962
7092
  return -1;
6963
- RG_DEFER_N(err_guard) { CloseSocket(sock); };
7093
+ K_DEFER_N(err_guard) { CloseSocket(sock); };
6964
7094
 
6965
7095
  if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
6966
7096
  #if defined(_WIN32)
@@ -7046,7 +7176,7 @@ struct WorkerData {
7046
7176
  };
7047
7177
 
7048
7178
  class AsyncPool {
7049
- RG_DELETE_COPY(AsyncPool)
7179
+ K_DELETE_COPY(AsyncPool)
7050
7180
 
7051
7181
  std::mutex pool_mutex;
7052
7182
  std::condition_variable pending_cv;
@@ -7088,7 +7218,7 @@ static thread_local bool async_running_task = false;
7088
7218
 
7089
7219
  Async::Async(int threads)
7090
7220
  {
7091
- RG_ASSERT(threads);
7221
+ K_ASSERT(threads);
7092
7222
 
7093
7223
  if (threads > 0) {
7094
7224
  pool = new AsyncPool(threads, false);
@@ -7112,7 +7242,7 @@ Async::Async(int threads)
7112
7242
 
7113
7243
  Async::Async(Async *parent)
7114
7244
  {
7115
- RG_ASSERT(parent);
7245
+ K_ASSERT(parent);
7116
7246
 
7117
7247
  pool = parent->pool;
7118
7248
  pool->RegisterAsync();
@@ -7170,9 +7300,9 @@ int Async::GetWorkerIdx()
7170
7300
 
7171
7301
  AsyncPool::AsyncPool(int threads, bool leak)
7172
7302
  {
7173
- if (threads > RG_ASYNC_MAX_THREADS) {
7174
- LogError("Async cannot use more than %1 threads", RG_ASYNC_MAX_THREADS);
7175
- 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;
7176
7306
  }
7177
7307
 
7178
7308
  // The first queue is for the main thread
@@ -7276,12 +7406,12 @@ void AsyncPool::AddTask(Async *async, int worker_idx, const std::function<bool()
7276
7406
 
7277
7407
  int prev_pending = pending_tasks++;
7278
7408
 
7279
- if (prev_pending >= RG_ASYNC_MAX_PENDING_TASKS) {
7409
+ if (prev_pending >= K_ASYNC_MAX_PENDING_TASKS) {
7280
7410
  int worker_idx = async_running_worker_idx;
7281
7411
 
7282
7412
  do {
7283
7413
  RunTasks(worker_idx, nullptr);
7284
- } while (pending_tasks >= RG_ASYNC_MAX_PENDING_TASKS);
7414
+ } while (pending_tasks >= K_ASYNC_MAX_PENDING_TASKS);
7285
7415
  } else if (!prev_pending) {
7286
7416
  std::lock_guard<std::mutex> lock_pool(pool_mutex);
7287
7417
 
@@ -7302,7 +7432,7 @@ void AsyncPool::RunWorker(int worker_idx)
7302
7432
  RunTasks(worker_idx, nullptr);
7303
7433
  lock_pool.lock();
7304
7434
 
7305
- 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++
7306
7436
  pending_cv.wait_for(lock_pool, duration, [&]() { return !!pending_tasks; });
7307
7437
  }
7308
7438
 
@@ -7316,7 +7446,7 @@ void AsyncPool::RunWorker(int worker_idx)
7316
7446
 
7317
7447
  void AsyncPool::SyncOn(Async *async, bool soon)
7318
7448
  {
7319
- RG_DEFER_C(pool = async_running_pool,
7449
+ K_DEFER_C(pool = async_running_pool,
7320
7450
  worker_idx = async_running_worker_idx) {
7321
7451
  async_running_pool = pool;
7322
7452
  async_running_worker_idx = worker_idx;
@@ -7388,7 +7518,7 @@ void AsyncPool::RunTask(Task *task)
7388
7518
  {
7389
7519
  Async *async = task->async;
7390
7520
 
7391
- RG_DEFER_C(running = async_running_task) { async_running_task = running; };
7521
+ K_DEFER_C(running = async_running_task) { async_running_task = running; };
7392
7522
  async_running_task = true;
7393
7523
 
7394
7524
  pending_tasks--;
@@ -7408,12 +7538,12 @@ void AsyncPool::RunTask(Task *task)
7408
7538
 
7409
7539
  Async::Async(int threads)
7410
7540
  {
7411
- RG_ASSERT(threads);
7541
+ K_ASSERT(threads);
7412
7542
  }
7413
7543
 
7414
7544
  Async::Async(Async *parent)
7415
7545
  {
7416
- RG_ASSERT(parent);
7546
+ K_ASSERT(parent);
7417
7547
  }
7418
7548
 
7419
7549
  Async::~Async()
@@ -7457,38 +7587,47 @@ int Async::GetWorkerCount()
7457
7587
  // Streams
7458
7588
  // ------------------------------------------------------------------------
7459
7589
 
7460
- static StreamReader StdInStream(STDIN_FILENO, "<stdin>");
7461
- static StreamWriter StdOutStream(STDOUT_FILENO, "<stdout>", (int)StreamWriterFlag::LineBuffer);
7462
- 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);
7593
+
7594
+ extern StreamReader *const StdIn = StdInStream.Get();
7595
+ extern StreamWriter *const StdOut = StdOutStream.Get();
7596
+ extern StreamWriter *const StdErr = StdErrStream.Get();
7463
7597
 
7464
- extern StreamReader *const StdIn = &StdInStream;
7465
- extern StreamWriter *const StdOut = &StdOutStream;
7466
- extern StreamWriter *const StdErr = &StdErrStream;
7598
+ static CreateDecompressorFunc *DecompressorFunctions[K_LEN(CompressionTypeNames)];
7599
+ static CreateCompressorFunc *CompressorFunctions[K_LEN(CompressionTypeNames)];
7467
7600
 
7468
- static CreateDecompressorFunc *DecompressorFunctions[RG_LEN(CompressionTypeNames)];
7469
- static CreateCompressorFunc *CompressorFunctions[RG_LEN(CompressionTypeNames)];
7601
+ K_EXIT(FlushStd)
7602
+ {
7603
+ StdOut->Flush();
7604
+ StdErr->Flush();
7605
+ }
7470
7606
 
7471
7607
  void StreamReader::SetDecoder(StreamDecoder *decoder)
7472
7608
  {
7473
- RG_ASSERT(decoder);
7474
- RG_ASSERT(!filename);
7475
- RG_ASSERT(!this->decoder);
7609
+ K_ASSERT(decoder);
7610
+ K_ASSERT(!filename);
7611
+ K_ASSERT(!this->decoder);
7476
7612
 
7477
7613
  this->decoder = decoder;
7478
7614
  }
7479
7615
 
7480
- 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,
7481
7617
  CompressionType compression_type)
7482
7618
  {
7483
7619
  Close(true);
7484
7620
 
7485
- RG_DEFER_N(err_guard) { error = true; };
7621
+ K_DEFER_N(err_guard) { error = true; };
7622
+
7623
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7486
7624
  error = false;
7487
7625
  raw_read = 0;
7488
7626
  read_total = 0;
7489
7627
  read_max = -1;
7490
7628
 
7491
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<memory>";
7629
+ K_ASSERT(filename);
7630
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
7492
7631
 
7493
7632
  source.type = SourceType::Memory;
7494
7633
  source.u.memory.buf = buf;
@@ -7501,18 +7640,20 @@ bool StreamReader::Open(Span<const uint8_t> buf, const char *filename,
7501
7640
  return true;
7502
7641
  }
7503
7642
 
7504
- 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)
7505
7644
  {
7506
7645
  Close(true);
7507
7646
 
7508
- RG_DEFER_N(err_guard) { error = true; };
7647
+ K_DEFER_N(err_guard) { error = true; };
7648
+
7649
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7509
7650
  error = false;
7510
7651
  raw_read = 0;
7511
7652
  read_total = 0;
7512
7653
  read_max = -1;
7513
7654
 
7514
- RG_ASSERT(fd >= 0);
7515
- RG_ASSERT(filename);
7655
+ K_ASSERT(fd >= 0);
7656
+ K_ASSERT(filename);
7516
7657
  this->filename = DuplicateString(filename, &str_alloc).ptr;
7517
7658
 
7518
7659
  source.type = SourceType::File;
@@ -7526,17 +7667,19 @@ bool StreamReader::Open(int fd, const char *filename, CompressionType compressio
7526
7667
  return true;
7527
7668
  }
7528
7669
 
7529
- OpenResult StreamReader::Open(const char *filename, CompressionType compression_type)
7670
+ OpenResult StreamReader::Open(const char *filename, unsigned int flags, CompressionType compression_type)
7530
7671
  {
7531
7672
  Close(true);
7532
7673
 
7533
- RG_DEFER_N(err_guard) { error = true; };
7674
+ K_DEFER_N(err_guard) { error = true; };
7675
+
7676
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7534
7677
  error = false;
7535
7678
  raw_read = 0;
7536
7679
  read_total = 0;
7537
7680
  read_max = -1;
7538
7681
 
7539
- RG_ASSERT(filename);
7682
+ K_ASSERT(filename);
7540
7683
  this->filename = DuplicateString(filename, &str_alloc).ptr;
7541
7684
 
7542
7685
  source.type = SourceType::File;
@@ -7554,18 +7697,21 @@ OpenResult StreamReader::Open(const char *filename, CompressionType compression_
7554
7697
  return OpenResult::Success;
7555
7698
  }
7556
7699
 
7557
- 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,
7558
7701
  CompressionType compression_type)
7559
7702
  {
7560
7703
  Close(true);
7561
7704
 
7562
- RG_DEFER_N(err_guard) { error = true; };
7705
+ K_DEFER_N(err_guard) { error = true; };
7706
+
7707
+ lazy = flags & (int)StreamReaderFlag::LazyFill;
7563
7708
  error = false;
7564
7709
  raw_read = 0;
7565
7710
  read_total = 0;
7566
7711
  read_max = -1;
7567
7712
 
7568
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<closure>";
7713
+ K_ASSERT(filename);
7714
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
7569
7715
 
7570
7716
  source.type = SourceType::Function;
7571
7717
  new (&source.u.func) std::function<Size(Span<uint8_t>)>(func);
@@ -7579,7 +7725,7 @@ bool StreamReader::Open(const std::function<Size(Span<uint8_t>)> &func, const ch
7579
7725
 
7580
7726
  bool StreamReader::Close(bool implicit)
7581
7727
  {
7582
- RG_ASSERT(implicit || this != StdIn);
7728
+ K_ASSERT(implicit || this != StdIn);
7583
7729
 
7584
7730
  if (decoder) {
7585
7731
  delete decoder;
@@ -7602,6 +7748,7 @@ bool StreamReader::Close(bool implicit)
7602
7748
  bool ret = !filename || !error;
7603
7749
 
7604
7750
  filename = nullptr;
7751
+ lazy = false;
7605
7752
  error = true;
7606
7753
  source.type = SourceType::Memory;
7607
7754
  source.eof = false;
@@ -7648,13 +7795,13 @@ bool StreamReader::Rewind()
7648
7795
 
7649
7796
  int StreamReader::GetDescriptor() const
7650
7797
  {
7651
- RG_ASSERT(source.type == SourceType::File);
7798
+ K_ASSERT(source.type == SourceType::File);
7652
7799
  return source.u.file.fd;
7653
7800
  }
7654
7801
 
7655
7802
  void StreamReader::SetDescriptorOwned(bool owned)
7656
7803
  {
7657
- RG_ASSERT(source.type == SourceType::File);
7804
+ K_ASSERT(source.type == SourceType::File);
7658
7805
  source.u.file.owned = owned;
7659
7806
  }
7660
7807
 
@@ -7695,7 +7842,7 @@ Size StreamReader::Read(Span<uint8_t> out_buf)
7695
7842
  return -1;
7696
7843
  }
7697
7844
 
7698
- if (eof)
7845
+ if (lazy || eof)
7699
7846
  break;
7700
7847
  }
7701
7848
 
@@ -7708,18 +7855,18 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
7708
7855
  if (error) [[unlikely]]
7709
7856
  return -1;
7710
7857
 
7711
- 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); };
7712
7859
 
7713
7860
  // Check virtual memory limits
7714
7861
  {
7715
- Size memory_max = RG_SIZE_MAX - out_buf->len - 1;
7862
+ Size memory_max = K_SIZE_MAX - out_buf->len - 1;
7716
7863
 
7717
7864
  if (memory_max <= 0) [[unlikely]] {
7718
7865
  LogError("Exhausted memory limit reading file '%1'", filename);
7719
7866
  return -1;
7720
7867
  }
7721
7868
 
7722
- RG_ASSERT(max_len);
7869
+ K_ASSERT(max_len);
7723
7870
  max_len = (max_len >= 0) ? std::min(max_len, memory_max) : memory_max;
7724
7871
  }
7725
7872
 
@@ -7747,7 +7894,7 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
7747
7894
  Size total_len = 0;
7748
7895
 
7749
7896
  while (!eof) {
7750
- 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);
7751
7898
  out_buf->Grow(grow);
7752
7899
 
7753
7900
  Size read_len = Read(out_buf->Available(), out_buf->end());
@@ -7814,7 +7961,7 @@ bool StreamReader::InitDecompressor(CompressionType type)
7814
7961
  }
7815
7962
 
7816
7963
  decoder = func(this, type);
7817
- RG_ASSERT(decoder);
7964
+ K_ASSERT(decoder);
7818
7965
  }
7819
7966
 
7820
7967
  return true;
@@ -7841,7 +7988,7 @@ Size StreamReader::ReadRaw(Size max_len, void *out_buf)
7841
7988
  max_len = std::min(max_len, (Size)UINT_MAX);
7842
7989
  read_len = _read(source.u.file.fd, out_buf, (unsigned int)max_len);
7843
7990
  #else
7844
- 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);
7845
7992
  #endif
7846
7993
  if (read_len < 0) {
7847
7994
  LogError("Error while reading file '%1': %2", filename, strerror(errno));
@@ -7867,7 +8014,7 @@ Size StreamReader::ReadRaw(Size max_len, void *out_buf)
7867
8014
 
7868
8015
  StreamDecompressorHelper::StreamDecompressorHelper(CompressionType compression_type, CreateDecompressorFunc *func)
7869
8016
  {
7870
- RG_ASSERT(!DecompressorFunctions[(int)compression_type]);
8017
+ K_ASSERT(!DecompressorFunctions[(int)compression_type]);
7871
8018
  DecompressorFunctions[(int)compression_type] = func;
7872
8019
  }
7873
8020
 
@@ -7883,9 +8030,9 @@ bool LineReader::Next(Span<char> *out_line)
7883
8030
 
7884
8031
  for (;;) {
7885
8032
  if (!view.len) {
7886
- buf.Grow(RG_LINE_READER_STEP_SIZE + 1);
8033
+ buf.Grow(K_LINE_READER_STEP_SIZE + 1);
7887
8034
 
7888
- 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());
7889
8036
  if (read_len < 0) {
7890
8037
  error = true;
7891
8038
  return false;
@@ -7911,7 +8058,7 @@ bool LineReader::Next(Span<char> *out_line)
7911
8058
 
7912
8059
  void LineReader::PushLogFilter()
7913
8060
  {
7914
- 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) {
7915
8062
  char ctx[1024];
7916
8063
 
7917
8064
  if (line_number > 0) {
@@ -7926,23 +8073,24 @@ void LineReader::PushLogFilter()
7926
8073
 
7927
8074
  void StreamWriter::SetEncoder(StreamEncoder *encoder)
7928
8075
  {
7929
- RG_ASSERT(encoder);
7930
- RG_ASSERT(!filename);
7931
- RG_ASSERT(!this->encoder);
8076
+ K_ASSERT(encoder);
8077
+ K_ASSERT(!filename);
8078
+ K_ASSERT(!this->encoder);
7932
8079
 
7933
8080
  this->encoder = encoder;
7934
8081
  }
7935
8082
 
7936
- bool StreamWriter::Open(HeapArray<uint8_t> *mem, const char *filename,
8083
+ bool StreamWriter::Open(HeapArray<uint8_t> *mem, const char *filename, unsigned int,
7937
8084
  CompressionType compression_type, CompressionSpeed compression_speed)
7938
8085
  {
7939
8086
  Close(true);
7940
8087
 
7941
- RG_DEFER_N(err_guard) { error = true; };
8088
+ K_DEFER_N(err_guard) { error = true; };
7942
8089
  error = false;
7943
8090
  raw_written = 0;
7944
8091
 
7945
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<memory>";
8092
+ K_ASSERT(filename);
8093
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
7946
8094
 
7947
8095
  dest.type = DestinationType::Memory;
7948
8096
  dest.u.mem.memory = mem;
@@ -7961,12 +8109,12 @@ bool StreamWriter::Open(int fd, const char *filename, unsigned int flags,
7961
8109
  {
7962
8110
  Close(true);
7963
8111
 
7964
- RG_DEFER_N(err_guard) { error = true; };
8112
+ K_DEFER_N(err_guard) { error = true; };
7965
8113
  error = false;
7966
8114
  raw_written = 0;
7967
8115
 
7968
- RG_ASSERT(fd >= 0);
7969
- RG_ASSERT(filename);
8116
+ K_ASSERT(fd >= 0);
8117
+ K_ASSERT(filename);
7970
8118
  this->filename = DuplicateString(filename, &str_alloc).ptr;
7971
8119
 
7972
8120
  InitFile(flags);
@@ -7986,11 +8134,11 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
7986
8134
  {
7987
8135
  Close(true);
7988
8136
 
7989
- RG_DEFER_N(err_guard) { error = true; };
8137
+ K_DEFER_N(err_guard) { error = true; };
7990
8138
  error = false;
7991
8139
  raw_written = 0;
7992
8140
 
7993
- RG_ASSERT(filename);
8141
+ K_ASSERT(filename);
7994
8142
  this->filename = DuplicateString(filename, &str_alloc).ptr;
7995
8143
 
7996
8144
  InitFile(flags);
@@ -8016,7 +8164,7 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
8016
8164
 
8017
8165
  if (has_proc) {
8018
8166
  const char *dirname = DuplicateString(directory, &str_alloc).ptr;
8019
- 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);
8020
8168
 
8021
8169
  if (dest.u.file.fd >= 0) {
8022
8170
  dest.u.file.owned = true;
@@ -8029,7 +8177,7 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
8029
8177
  #endif
8030
8178
 
8031
8179
  if (!dest.u.file.owned) {
8032
- const char *basename = SplitStrReverseAny(filename, RG_PATH_SEPARATORS).ptr;
8180
+ const char *basename = SplitStrReverseAny(filename, K_PATH_SEPARATORS).ptr;
8033
8181
 
8034
8182
  dest.u.file.tmp_filename = CreateUniqueFile(directory, basename, ".tmp", &str_alloc, &dest.u.file.fd);
8035
8183
  if (!dest.u.file.tmp_filename)
@@ -8056,16 +8204,17 @@ bool StreamWriter::Open(const char *filename, unsigned int flags,
8056
8204
  return true;
8057
8205
  }
8058
8206
 
8059
- 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,
8060
8208
  CompressionType compression_type, CompressionSpeed compression_speed)
8061
8209
  {
8062
8210
  Close(true);
8063
8211
 
8064
- RG_DEFER_N(err_guard) { error = true; };
8212
+ K_DEFER_N(err_guard) { error = true; };
8065
8213
  error = false;
8066
8214
  raw_written = 0;
8067
8215
 
8068
- this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<closure>";
8216
+ K_ASSERT(filename);
8217
+ this->filename = DuplicateString(filename, &str_alloc).ptr;
8069
8218
 
8070
8219
  dest.type = DestinationType::Function;
8071
8220
  new (&dest.u.func) std::function<bool(Span<const uint8_t>)>(func);
@@ -8160,12 +8309,12 @@ bool StreamWriter::Flush()
8160
8309
  case DestinationType::Function: return true;
8161
8310
  }
8162
8311
 
8163
- RG_UNREACHABLE();
8312
+ K_UNREACHABLE();
8164
8313
  }
8165
8314
 
8166
8315
  int StreamWriter::GetDescriptor() const
8167
8316
  {
8168
- RG_ASSERT(dest.type == DestinationType::BufferedFile ||
8317
+ K_ASSERT(dest.type == DestinationType::BufferedFile ||
8169
8318
  dest.type == DestinationType::LineFile ||
8170
8319
  dest.type == DestinationType::DirectFile);
8171
8320
 
@@ -8174,7 +8323,7 @@ int StreamWriter::GetDescriptor() const
8174
8323
 
8175
8324
  void StreamWriter::SetDescriptorOwned(bool owned)
8176
8325
  {
8177
- RG_ASSERT(dest.type == DestinationType::BufferedFile ||
8326
+ K_ASSERT(dest.type == DestinationType::BufferedFile ||
8178
8327
  dest.type == DestinationType::LineFile ||
8179
8328
  dest.type == DestinationType::DirectFile);
8180
8329
 
@@ -8200,8 +8349,8 @@ bool StreamWriter::Write(Span<const uint8_t> buf)
8200
8349
 
8201
8350
  bool StreamWriter::Close(bool implicit)
8202
8351
  {
8203
- RG_ASSERT(implicit || this != StdOut);
8204
- RG_ASSERT(implicit || this != StdErr);
8352
+ K_ASSERT(implicit || this != StdOut);
8353
+ K_ASSERT(implicit || this != StdErr);
8205
8354
 
8206
8355
  if (encoder) {
8207
8356
  error = error || !encoder->Finalize();
@@ -8260,7 +8409,7 @@ bool StreamWriter::Close(bool implicit)
8260
8409
  // a temporary file and let RenameFile() handle the final step. Should be rare!
8261
8410
  if (!linked) {
8262
8411
  Span<const char> directory = GetPathDirectory(filename);
8263
- const char *basename = SplitStrReverseAny(filename, RG_PATH_SEPARATORS).ptr;
8412
+ const char *basename = SplitStrReverseAny(filename, K_PATH_SEPARATORS).ptr;
8264
8413
 
8265
8414
  dest.u.file.tmp_filename = CreateUniquePath(directory, basename, ".tmp", &str_alloc, [&](const char *path) {
8266
8415
  return !linkat(AT_FDCWD, proc, AT_FDCWD, path, AT_SYMLINK_FOLLOW);
@@ -8305,7 +8454,7 @@ bool StreamWriter::Close(bool implicit)
8305
8454
  UnlinkFile(filename);
8306
8455
  }
8307
8456
 
8308
- MemSet(&dest.u.file, 0, RG_SIZE(dest.u.file));
8457
+ MemSet(&dest.u.file, 0, K_SIZE(dest.u.file));
8309
8458
  } break;
8310
8459
 
8311
8460
  case DestinationType::Function: {
@@ -8329,9 +8478,9 @@ void StreamWriter::InitFile(unsigned int flags)
8329
8478
  bool direct = (flags & (int)StreamWriterFlag::NoBuffer);
8330
8479
  bool line = (flags & (int)StreamWriterFlag::LineBuffer);
8331
8480
 
8332
- RG_ASSERT(!direct || !line);
8481
+ K_ASSERT(!direct || !line);
8333
8482
 
8334
- MemSet(&dest.u.file, 0, RG_SIZE(dest.u.file));
8483
+ MemSet(&dest.u.file, 0, K_SIZE(dest.u.file));
8335
8484
 
8336
8485
  if (direct) {
8337
8486
  dest.type = DestinationType::DirectFile;
@@ -8346,15 +8495,15 @@ void StreamWriter::InitFile(unsigned int flags)
8346
8495
 
8347
8496
  bool StreamWriter::FlushBuffer()
8348
8497
  {
8349
- RG_ASSERT(!error);
8350
- RG_ASSERT(dest.type == DestinationType::BufferedFile ||
8498
+ K_ASSERT(!error);
8499
+ K_ASSERT(dest.type == DestinationType::BufferedFile ||
8351
8500
  dest.type == DestinationType::LineFile);
8352
8501
 
8353
8502
  while (dest.u.file.buf_used) {
8354
8503
  #if defined(_WIN32)
8355
8504
  Size write_len = _write(dest.u.file.fd, dest.u.file.buf.ptr, (unsigned int)dest.u.file.buf_used);
8356
8505
  #else
8357
- 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);
8358
8507
  #endif
8359
8508
 
8360
8509
  if (write_len < 0) {
@@ -8385,7 +8534,7 @@ bool StreamWriter::InitCompressor(CompressionType type, CompressionSpeed speed)
8385
8534
  }
8386
8535
 
8387
8536
  encoder = func(this, type, speed);
8388
- RG_ASSERT(encoder);
8537
+ K_ASSERT(encoder);
8389
8538
  }
8390
8539
 
8391
8540
  return true;
@@ -8472,7 +8621,7 @@ bool StreamWriter::WriteRaw(Span<const uint8_t> buf)
8472
8621
  unsigned int int_len = (unsigned int)std::min(buf.len, (Size)UINT_MAX);
8473
8622
  Size write_len = _write(dest.u.file.fd, buf.ptr, int_len);
8474
8623
  #else
8475
- 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);
8476
8625
  #endif
8477
8626
 
8478
8627
  if (write_len < 0) {
@@ -8507,14 +8656,14 @@ bool StreamWriter::WriteRaw(Span<const uint8_t> buf)
8507
8656
 
8508
8657
  StreamCompressorHelper::StreamCompressorHelper(CompressionType compression_type, CreateCompressorFunc *func)
8509
8658
  {
8510
- RG_ASSERT(!CompressorFunctions[(int)compression_type]);
8659
+ K_ASSERT(!CompressorFunctions[(int)compression_type]);
8511
8660
  CompressorFunctions[(int)compression_type] = func;
8512
8661
  }
8513
8662
 
8514
8663
  bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer, Span<uint8_t> buf,
8515
8664
  FunctionRef<void(int64_t, int64_t)> progress)
8516
8665
  {
8517
- RG_ASSERT(buf.len >= Kibibytes(2));
8666
+ K_ASSERT(buf.len >= Kibibytes(2));
8518
8667
 
8519
8668
  if (!reader->IsValid())
8520
8669
  return false;
@@ -8561,7 +8710,7 @@ IniParser::LineType IniParser::FindNextLine(IniProperty *out_prop)
8561
8710
  if (error) [[unlikely]]
8562
8711
  return LineType::Exit;
8563
8712
 
8564
- RG_DEFER_N(err_guard) { error = true; };
8713
+ K_DEFER_N(err_guard) { error = true; };
8565
8714
 
8566
8715
  Span<char> line;
8567
8716
  while (reader.Next(&line)) {
@@ -8655,7 +8804,7 @@ bool ReloadAssets()
8655
8804
  SplitStrReverse(prefix, '.', &prefix);
8656
8805
  #endif
8657
8806
 
8658
- Fmt(assets_filename, "%1_assets%2", prefix, RG_SHARED_LIBRARY_EXTENSION);
8807
+ Fmt(assets_filename, "%1_assets%2", prefix, K_SHARED_LIBRARY_EXTENSION);
8659
8808
  }
8660
8809
 
8661
8810
  // Check library time
@@ -8684,7 +8833,7 @@ bool ReloadAssets()
8684
8833
  LogError("Cannot load library '%1'", assets_filename);
8685
8834
  return false;
8686
8835
  }
8687
- RG_DEFER { FreeLibrary(h); };
8836
+ K_DEFER { FreeLibrary(h); };
8688
8837
 
8689
8838
  lib_assets = (const Span<const AssetInfo> *)(void *)GetProcAddress(h, "EmbedAssets");
8690
8839
  #else
@@ -8693,12 +8842,12 @@ bool ReloadAssets()
8693
8842
  LogError("Cannot load library '%1': %2", assets_filename, dlerror());
8694
8843
  return false;
8695
8844
  }
8696
- RG_DEFER { dlclose(h); };
8845
+ K_DEFER { dlclose(h); };
8697
8846
 
8698
8847
  lib_assets = (const Span<const AssetInfo> *)dlsym(h, "EmbedAssets");
8699
8848
  #endif
8700
8849
  if (!lib_assets) {
8701
- LogError("Cannot find symbol '%1' in library '%2'", "EmbedAssets", assets_filename);
8850
+ LogError("Cannot find symbol 'EmbedAssets' in library '%1'", assets_filename);
8702
8851
  return false;
8703
8852
  }
8704
8853
 
@@ -8729,7 +8878,7 @@ Span<const AssetInfo> GetEmbedAssets()
8729
8878
  {
8730
8879
  if (!assets_ready) {
8731
8880
  ReloadAssets();
8732
- RG_ASSERT(assets_ready);
8881
+ K_ASSERT(assets_ready);
8733
8882
  }
8734
8883
 
8735
8884
  return assets;
@@ -8739,7 +8888,7 @@ const AssetInfo *FindEmbedAsset(const char *name)
8739
8888
  {
8740
8889
  if (!assets_ready) {
8741
8890
  ReloadAssets();
8742
- RG_ASSERT(assets_ready);
8891
+ K_ASSERT(assets_ready);
8743
8892
  }
8744
8893
 
8745
8894
  return assets_map.FindValue(name, nullptr);
@@ -8798,10 +8947,10 @@ bool PatchFile(StreamReader *reader, StreamWriter *writer,
8798
8947
  bool PatchFile(Span<const uint8_t> data, StreamWriter *writer,
8799
8948
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8800
8949
  {
8801
- StreamReader reader(data, nullptr);
8950
+ StreamReader reader(data, "<asset>");
8802
8951
 
8803
8952
  if (!PatchFile(&reader, writer, func)) {
8804
- RG_ASSERT(reader.IsValid());
8953
+ K_ASSERT(reader.IsValid());
8805
8954
  return false;
8806
8955
  }
8807
8956
 
@@ -8811,10 +8960,10 @@ bool PatchFile(Span<const uint8_t> data, StreamWriter *writer,
8811
8960
  bool PatchFile(const AssetInfo &asset, StreamWriter *writer,
8812
8961
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8813
8962
  {
8814
- StreamReader reader(asset.data, nullptr, asset.compression_type);
8963
+ StreamReader reader(asset.data, "<asset>", 0, asset.compression_type);
8815
8964
 
8816
8965
  if (!PatchFile(&reader, writer, func)) {
8817
- RG_ASSERT(reader.IsValid());
8966
+ K_ASSERT(reader.IsValid());
8818
8967
  return false;
8819
8968
  }
8820
8969
 
@@ -8824,15 +8973,15 @@ bool PatchFile(const AssetInfo &asset, StreamWriter *writer,
8824
8973
  Span<const uint8_t> PatchFile(Span<const uint8_t> data, Allocator *alloc,
8825
8974
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8826
8975
  {
8827
- RG_ASSERT(alloc);
8976
+ K_ASSERT(alloc);
8828
8977
 
8829
8978
  HeapArray<uint8_t> buf(alloc);
8830
- StreamWriter writer(&buf, nullptr);
8979
+ StreamWriter writer(&buf, "<asset>");
8831
8980
 
8832
8981
  PatchFile(data, &writer, func);
8833
8982
 
8834
8983
  bool success = writer.Close();
8835
- RG_ASSERT(success);
8984
+ K_ASSERT(success);
8836
8985
 
8837
8986
  buf.Grow(1);
8838
8987
  buf.ptr[buf.len] = 0;
@@ -8843,15 +8992,15 @@ Span<const uint8_t> PatchFile(Span<const uint8_t> data, Allocator *alloc,
8843
8992
  Span<const uint8_t> PatchFile(const AssetInfo &asset, Allocator *alloc,
8844
8993
  FunctionRef<void(Span<const char>, StreamWriter *)> func)
8845
8994
  {
8846
- RG_ASSERT(alloc);
8995
+ K_ASSERT(alloc);
8847
8996
 
8848
8997
  HeapArray<uint8_t> buf(alloc);
8849
- StreamWriter writer(&buf, nullptr, asset.compression_type);
8998
+ StreamWriter writer(&buf, "<asset>", 0, asset.compression_type);
8850
8999
 
8851
9000
  PatchFile(asset, &writer, func);
8852
9001
 
8853
9002
  bool success = writer.Close();
8854
- RG_ASSERT(success);
9003
+ K_ASSERT(success);
8855
9004
 
8856
9005
  buf.Grow(1);
8857
9006
  buf.ptr[buf.len] = 0;
@@ -8867,7 +9016,108 @@ Span<const char> PatchFile(Span<const char> data, Allocator *alloc,
8867
9016
  }
8868
9017
 
8869
9018
  // ------------------------------------------------------------------------
8870
- // 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
8871
9121
  // ------------------------------------------------------------------------
8872
9122
 
8873
9123
  static inline bool IsOption(const char *arg)
@@ -8936,8 +9186,8 @@ const char *OptionParser::Next()
8936
9186
  // option up to '=' in our buffer. And store the part after '=' as the
8937
9187
  // current value.
8938
9188
  Size len = needle - opt;
8939
- if (len > RG_SIZE(buf) - 1) {
8940
- len = RG_SIZE(buf) - 1;
9189
+ if (len > K_SIZE(buf) - 1) {
9190
+ len = K_SIZE(buf) - 1;
8941
9191
  }
8942
9192
  MemCpy(buf, opt, len);
8943
9193
  buf[len] = 0;
@@ -9019,8 +9269,8 @@ void OptionParser::ConsumeNonOptions(HeapArray<const char *> *non_options)
9019
9269
 
9020
9270
  bool OptionParser::Test(const char *test1, const char *test2, OptionType type)
9021
9271
  {
9022
- RG_ASSERT(test1 && IsOption(test1));
9023
- RG_ASSERT(!test2 || IsOption(test2));
9272
+ K_ASSERT(test1 && IsOption(test1));
9273
+ K_ASSERT(!test2 || IsOption(test2));
9024
9274
 
9025
9275
  if (TestStr(test1, current_option) || (test2 && TestStr(test2, current_option))) {
9026
9276
  switch (type) {
@@ -9151,11 +9401,11 @@ bool ConsolePrompter::Read(Span<const char> *out_str)
9151
9401
  #if !defined(_WIN32) && !defined(__wasm__)
9152
9402
  struct sigaction old_sa;
9153
9403
  IgnoreSigWinch(&old_sa);
9154
- RG_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9404
+ K_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9155
9405
  #endif
9156
9406
 
9157
9407
  if (FileIsVt100(STDERR_FILENO) && EnableRawMode()) {
9158
- RG_DEFER {
9408
+ K_DEFER {
9159
9409
  Print(StdErr, "%!0");
9160
9410
  DisableRawMode();
9161
9411
  };
@@ -9168,16 +9418,16 @@ bool ConsolePrompter::Read(Span<const char> *out_str)
9168
9418
 
9169
9419
  Size ConsolePrompter::ReadEnum(Span<const PromptChoice> choices, Size value)
9170
9420
  {
9171
- RG_ASSERT(value < choices.len);
9421
+ K_ASSERT(value < choices.len);
9172
9422
 
9173
9423
  #if !defined(_WIN32) && !defined(__wasm__)
9174
9424
  struct sigaction old_sa;
9175
9425
  IgnoreSigWinch(&old_sa);
9176
- RG_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9426
+ K_DEFER { sigaction(SIGWINCH, &old_sa, nullptr); };
9177
9427
  #endif
9178
9428
 
9179
9429
  if (FileIsVt100(STDERR_FILENO) && EnableRawMode()) {
9180
- RG_DEFER {
9430
+ K_DEFER {
9181
9431
  Print(StdErr, "%!0");
9182
9432
  DisableRawMode();
9183
9433
  };
@@ -9210,7 +9460,7 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
9210
9460
  {
9211
9461
  StdErr->Flush();
9212
9462
 
9213
- prompt_columns = ComputeWidth(prompt);
9463
+ prompt_columns = ComputeUnicodeWidth(prompt) + 1;
9214
9464
  str_offset = str.len;
9215
9465
 
9216
9466
  RenderRaw();
@@ -9227,7 +9477,7 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
9227
9477
  LocalArray<char, 16> buf;
9228
9478
 
9229
9479
  const auto match_escape = [&](const char *seq) {
9230
- RG_ASSERT(strlen(seq) < RG_SIZE(buf.data));
9480
+ K_ASSERT(strlen(seq) < K_SIZE(buf.data));
9231
9481
 
9232
9482
  for (Size i = 0; seq[i]; i++) {
9233
9483
  if (i >= buf.len) {
@@ -9456,7 +9706,7 @@ Size ConsolePrompter::ReadRawEnum(Span<const PromptChoice> choices, Size value)
9456
9706
  LocalArray<char, 16> buf;
9457
9707
 
9458
9708
  const auto match_escape = [&](const char *seq) {
9459
- RG_ASSERT(strlen(seq) < RG_SIZE(buf.data));
9709
+ K_ASSERT(strlen(seq) < K_SIZE(buf.data));
9460
9710
 
9461
9711
  for (Size i = 0; seq[i]; i++) {
9462
9712
  if (i >= buf.len) {
@@ -9536,7 +9786,7 @@ Size ConsolePrompter::ReadRawEnum(Span<const PromptChoice> choices, Size value)
9536
9786
 
9537
9787
  bool ConsolePrompter::ReadBuffered(Span<const char> *out_str)
9538
9788
  {
9539
- prompt_columns = ComputeWidth(prompt);
9789
+ prompt_columns = ComputeUnicodeWidth(prompt) + 1;
9540
9790
 
9541
9791
  RenderBuffered();
9542
9792
 
@@ -9667,8 +9917,8 @@ Size ConsolePrompter::FindBackward(Size offset, const char *chars)
9667
9917
 
9668
9918
  void ConsolePrompter::Delete(Size start, Size end)
9669
9919
  {
9670
- RG_ASSERT(start >= 0);
9671
- RG_ASSERT(end >= start && end <= str.len);
9920
+ K_ASSERT(start >= 0);
9921
+ K_ASSERT(end >= start && end <= str.len);
9672
9922
 
9673
9923
  MemMove(str.ptr + start, str.ptr + end, str.len - end);
9674
9924
  str.len -= end - start;
@@ -9685,15 +9935,16 @@ void ConsolePrompter::FormatChoices(Span<const PromptChoice> choices, Size value
9685
9935
  int align = 0;
9686
9936
 
9687
9937
  for (const PromptChoice &choice: choices) {
9688
- align = std::max(align, (int)strlen(choice.str));
9938
+ align = std::max(align, (int)ComputeUnicodeWidth(choice.str));
9689
9939
  }
9690
9940
 
9691
9941
  str.RemoveFrom(0);
9692
9942
  str.Append('\n');
9693
9943
  for (Size i = 0; i < choices.len; i++) {
9694
9944
  const PromptChoice &choice = choices[i];
9945
+ int pad = align - ComputeUnicodeWidth(choice.str);
9695
9946
 
9696
- Fmt(&str, " [%1] %2 ", choice.c, FmtArg(choice.str).Pad(align));
9947
+ Fmt(&str, " [%1] %2%3 ", choice.c, choice.str, FmtArg(' ').Repeat(pad));
9697
9948
  if (i == value) {
9698
9949
  str_offset = str.len;
9699
9950
  }
@@ -9706,7 +9957,7 @@ void ConsolePrompter::RenderRaw()
9706
9957
  columns = GetConsoleSize().x;
9707
9958
  rows = 0;
9708
9959
 
9709
- int mask_columns = mask ? ComputeWidth(mask) : 0;
9960
+ int mask_columns = mask ? ComputeUnicodeWidth(mask) : 0;
9710
9961
 
9711
9962
  // Hide cursor during refresh
9712
9963
  StdErr->Write("\x1B[?25l");
@@ -9719,7 +9970,7 @@ void ConsolePrompter::RenderRaw()
9719
9970
  Size i = 0;
9720
9971
  int x2 = prompt_columns;
9721
9972
 
9722
- Print(StdErr, "\r%!0%1%!..+", prompt);
9973
+ Print(StdErr, "\r%!0%1 %!..+", prompt);
9723
9974
 
9724
9975
  for (;;) {
9725
9976
  if (i == str_offset) {
@@ -9730,7 +9981,7 @@ void ConsolePrompter::RenderRaw()
9730
9981
  break;
9731
9982
 
9732
9983
  Size bytes = std::min((Size)CountUtf8Bytes(str[i]), str.len - i);
9733
- int width = mask ? mask_columns : ComputeWidth(str.Take(i, bytes));
9984
+ int width = mask ? mask_columns : ComputeUnicodeWidth(str.Take(i, bytes));
9734
9985
 
9735
9986
  if (x2 + width >= columns || str[i] == '\n') {
9736
9987
  FmtArg prefix = FmtArg(' ').Repeat(prompt_columns - 1);
@@ -9774,7 +10025,7 @@ void ConsolePrompter::RenderBuffered()
9774
10025
  Span<const char> remain = str;
9775
10026
  Span<const char> line = SplitStr(remain, '\n', &remain);
9776
10027
 
9777
- Print(StdErr, "%1%2", prompt, line);
10028
+ Print(StdErr, "%1 %2", prompt, line);
9778
10029
  while (remain.len) {
9779
10030
  line = SplitStr(remain, '\n', &remain);
9780
10031
  Print(StdErr, "\n%1%2", FmtArg(' ').Repeat(prompt_columns), line);
@@ -9941,25 +10192,6 @@ error:
9941
10192
  #endif
9942
10193
  }
9943
10194
 
9944
- int ConsolePrompter::ComputeWidth(Span<const char> str)
9945
- {
9946
- Size i = 0;
9947
- int width = 0;
9948
-
9949
- while (i < str.len) {
9950
- int32_t uc;
9951
- Size bytes = DecodeUtf8(str, i, &uc);
9952
-
9953
- if (!bytes) [[unlikely]]
9954
- return false;
9955
-
9956
- i += bytes;
9957
- width += ComputeCharacterWidth(uc);
9958
- }
9959
-
9960
- return width;
9961
- }
9962
-
9963
10195
  void ConsolePrompter::EnsureNulTermination()
9964
10196
  {
9965
10197
  str.Grow(1);
@@ -9968,7 +10200,7 @@ void ConsolePrompter::EnsureNulTermination()
9968
10200
 
9969
10201
  const char *Prompt(const char *prompt, const char *default_value, const char *mask, Allocator *alloc)
9970
10202
  {
9971
- RG_ASSERT(alloc);
10203
+ K_ASSERT(alloc);
9972
10204
 
9973
10205
  ConsolePrompter prompter;
9974
10206
 
@@ -9988,7 +10220,7 @@ const char *Prompt(const char *prompt, const char *default_value, const char *ma
9988
10220
 
9989
10221
  Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value)
9990
10222
  {
9991
- #if defined(RG_DEBUG)
10223
+ #if defined(K_DEBUG)
9992
10224
  {
9993
10225
  HashSet<char> keys;
9994
10226
 
@@ -9997,7 +10229,7 @@ Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value
9997
10229
  }
9998
10230
 
9999
10231
  bool duplicates = (keys.table.count < choices.len);
10000
- RG_ASSERT(!duplicates);
10232
+ K_ASSERT(!duplicates);
10001
10233
  }
10002
10234
  #endif
10003
10235
 
@@ -10010,7 +10242,7 @@ Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value
10010
10242
  Size PromptEnum(const char *prompt, Span<const char *const> strings, Size value)
10011
10243
  {
10012
10244
  static const char literals[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
10013
- RG_ASSERT(strings.len <= RG_LEN(literals));
10245
+ K_ASSERT(strings.len <= K_LEN(literals));
10014
10246
 
10015
10247
  HeapArray<PromptChoice> choices;
10016
10248
 
@@ -10065,7 +10297,7 @@ bool CanCompressFile(const char *filename)
10065
10297
  const char *ptr = GetPathExtension(filename).ptr;
10066
10298
 
10067
10299
  Size i = 0;
10068
- while (i < RG_SIZE(extension) - 1 && ptr[i]) {
10300
+ while (i < K_SIZE(extension) - 1 && ptr[i]) {
10069
10301
  extension[i] = LowerAscii(ptr[i]);
10070
10302
  i++;
10071
10303
  }
@@ -10107,10 +10339,27 @@ bool CanCompressFile(const char *filename)
10107
10339
  // Unicode
10108
10340
  // ------------------------------------------------------------------------
10109
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
+
10110
10359
  static bool TestUnicodeTable(Span<const int32_t> table, int32_t uc)
10111
10360
  {
10112
- RG_ASSERT(table.len > 0);
10113
- RG_ASSERT(table.len % 2 == 0);
10361
+ K_ASSERT(table.len > 0);
10362
+ K_ASSERT(table.len % 2 == 0);
10114
10363
 
10115
10364
  auto it = std::upper_bound(table.begin(), table.end(), uc,
10116
10365
  [](int32_t uc, int32_t x) { return uc < x; });
@@ -10120,10 +10369,11 @@ static bool TestUnicodeTable(Span<const int32_t> table, int32_t uc)
10120
10369
  return idx & 0x1;
10121
10370
  }
10122
10371
 
10123
- int ComputeCharacterWidth(int32_t uc)
10372
+ static inline int ComputeCharacterWidth(int32_t uc)
10124
10373
  {
10125
- if (uc < 32)
10126
- return 0;
10374
+ // Fast path
10375
+ if (uc < 128)
10376
+ return (uc >= 32) ? 1 : 0;
10127
10377
 
10128
10378
  if (TestUnicodeTable(WcWidthNull, uc))
10129
10379
  return 0;
@@ -10133,6 +10383,25 @@ int ComputeCharacterWidth(int32_t uc)
10133
10383
  return 1;
10134
10384
  }
10135
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
+
10136
10405
  bool IsXidStart(int32_t uc)
10137
10406
  {
10138
10407
  if (IsAsciiAlpha(uc))
@@ -10165,7 +10434,7 @@ uint32_t CRC32(uint32_t state, Span<const uint8_t> buf)
10165
10434
  {
10166
10435
  state = ~state;
10167
10436
 
10168
- Size right = buf.len & (RG_SIZE_MAX - 3);
10437
+ Size right = buf.len & (K_SIZE_MAX - 3);
10169
10438
 
10170
10439
  for (Size i = 0; i < right; i += 4) {
10171
10440
  state = (state >> 8) ^ Crc32Table[(state ^ buf[i + 0]) & 0xFF];
@@ -10184,7 +10453,7 @@ uint32_t CRC32C(uint32_t state, Span<const uint8_t> buf)
10184
10453
  {
10185
10454
  state = ~state;
10186
10455
 
10187
- Size right = buf.len & (RG_SIZE_MAX - 3);
10456
+ Size right = buf.len & (K_SIZE_MAX - 3);
10188
10457
 
10189
10458
  for (Size i = 0; i < right; i += 4) {
10190
10459
  state = (state >> 8) ^ Crc32CTable[(state ^ buf[i + 0]) & 0xFF];
@@ -10230,16 +10499,12 @@ uint64_t CRC64xz(uint64_t state, Span<const uint8_t> buf)
10230
10499
  {
10231
10500
  state = ~state;
10232
10501
 
10233
- Size left = std::min(buf.len, (Size)(AlignUp(buf.ptr, 16) - buf.ptr));
10234
- Size right = std::max(left, (Size)(AlignDown(buf.end(), 16) - buf.ptr));
10502
+ Size len16 = buf.len / 16 * 16;
10235
10503
 
10236
- for (Size i = 0; i < left; i++) {
10237
- state = XzUpdate1(state, buf[i]);
10238
- }
10239
- for (Size i = left; i < right; i += 16) {
10504
+ for (Size i = 0; i < len16; i += 16) {
10240
10505
  state = XzUpdate16(state, buf.ptr + i);
10241
10506
  }
10242
- for (Size i = right; i < buf.len; i++) {
10507
+ for (Size i = len16; i < buf.len; i++) {
10243
10508
  state = XzUpdate1(state, buf[i]);
10244
10509
  }
10245
10510
 
@@ -10277,16 +10542,12 @@ uint64_t CRC64nvme(uint64_t state, Span<const uint8_t> buf)
10277
10542
  {
10278
10543
  state = ~state;
10279
10544
 
10280
- Size left = std::min(buf.len, (Size)(AlignUp(buf.ptr, 16) - buf.ptr));
10281
- Size right = std::max(left, (Size)(AlignDown(buf.end(), 16) - buf.ptr));
10545
+ Size len16 = buf.len / 16 * 16;
10282
10546
 
10283
- for (Size i = 0; i < left; i++) {
10284
- state = NvmeUpdate1(state, buf[i]);
10285
- }
10286
- for (Size i = left; i < right; i += 16) {
10547
+ for (Size i = 0; i < len16; i += 16) {
10287
10548
  state = NvmeUpdate16(state, buf.ptr + i);
10288
10549
  }
10289
- for (Size i = right; i < buf.len; i++) {
10550
+ for (Size i = len16; i < buf.len; i++) {
10290
10551
  state = NvmeUpdate1(state, buf[i]);
10291
10552
  }
10292
10553