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