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