koffi 2.14.1 → 2.15.0
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 +19 -0
- 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/assets.ini +2 -1
- package/doc/build.sh +9 -0
- package/doc/pages/404.md +17 -0
- package/doc/pages/index.md +1 -1
- package/doc/pages/misc.md +16 -11
- package/doc/pages.ini +4 -0
- package/doc/static/highlight.js +2 -14
- package/doc/static/koffi.css +3 -15
- package/doc/static/print.css +2 -14
- package/index.d.ts +29 -24
- package/index.js +8 -8
- package/indirect.js +8 -8
- package/{src/core → lib/native}/base/base.cc +1058 -630
- package/{src/core → lib/native}/base/base.hh +334 -165
- package/{src/core → lib/native}/base/crc.inc +2 -20
- package/lib/native/base/crc_gen.py +72 -0
- package/{src/core → lib/native}/base/mimetypes.inc +2 -20
- package/{src/core → lib/native}/base/mimetypes_gen.py +2 -21
- package/lib/native/base/tower.cc +821 -0
- package/lib/native/base/tower.hh +81 -0
- package/{src/core → lib/native}/base/unicode.inc +2 -20
- package/{src/core → lib/native}/base/unicode_gen.py +4 -41
- package/package.json +1 -1
- package/src/cnoke/assets/FindCNoke.cmake +8 -20
- package/src/cnoke/assets/win_delay_hook.c +2 -20
- package/src/cnoke/cnoke.js +2 -21
- package/src/cnoke/src/builder.js +2 -20
- package/src/cnoke/src/index.js +2 -20
- package/src/cnoke/src/tools.js +2 -20
- package/src/koffi/CMakeLists.txt +19 -22
- package/src/koffi/cmake/raylib.cmake +5 -22
- package/src/koffi/cmake/sqlite3.cmake +2 -20
- package/src/koffi/src/abi_arm32.cc +7 -25
- package/src/koffi/src/abi_arm32_asm.S +2 -20
- package/src/koffi/src/abi_arm64.cc +7 -25
- package/src/koffi/src/abi_arm64_asm.S +2 -20
- package/src/koffi/src/abi_arm64_asm.asm +2 -20
- package/src/koffi/src/abi_loong64.cc +2 -20
- package/src/koffi/src/abi_loong64_asm.S +2 -20
- package/src/koffi/src/abi_riscv64.cc +7 -25
- package/src/koffi/src/abi_riscv64_asm.S +2 -20
- package/src/koffi/src/abi_x64_sysv.cc +7 -25
- package/src/koffi/src/abi_x64_sysv_asm.S +2 -20
- package/src/koffi/src/abi_x64_win.cc +12 -30
- package/src/koffi/src/abi_x64_win_asm.asm +2 -20
- package/src/koffi/src/abi_x86.cc +7 -25
- package/src/koffi/src/abi_x86_asm.S +2 -20
- package/src/koffi/src/abi_x86_asm.asm +2 -20
- package/src/koffi/src/call.cc +25 -45
- package/src/koffi/src/call.hh +3 -21
- package/src/koffi/src/errno.inc +2 -20
- package/src/koffi/src/ffi.cc +62 -62
- package/src/koffi/src/ffi.hh +14 -29
- package/src/koffi/src/init.js +2 -20
- package/src/koffi/src/parser.cc +13 -27
- package/src/koffi/src/parser.hh +3 -21
- package/src/koffi/src/trampolines/armasm.inc +0 -21
- package/src/koffi/src/trampolines/gnu.inc +0 -21
- package/src/koffi/src/trampolines/masm32.inc +0 -21
- package/src/koffi/src/trampolines/masm64.inc +0 -21
- package/src/koffi/src/trampolines/prototypes.inc +0 -21
- package/src/koffi/src/util.cc +44 -59
- package/src/koffi/src/util.hh +6 -24
- package/src/koffi/src/uv.cc +193 -0
- package/src/koffi/src/uv.def +10 -0
- package/src/koffi/src/uv.hh +40 -0
- package/src/koffi/src/win32.cc +2 -20
- package/src/koffi/src/win32.hh +3 -21
- package/vendor/node-api-headers/include/uv/aix.h +32 -0
- package/vendor/node-api-headers/include/uv/bsd.h +34 -0
- package/vendor/node-api-headers/include/uv/darwin.h +61 -0
- package/vendor/node-api-headers/include/uv/errno.h +483 -0
- package/vendor/node-api-headers/include/uv/linux.h +34 -0
- package/vendor/node-api-headers/include/uv/os390.h +33 -0
- package/vendor/node-api-headers/include/uv/posix.h +31 -0
- package/vendor/node-api-headers/include/uv/sunos.h +44 -0
- package/vendor/node-api-headers/include/uv/threadpool.h +37 -0
- package/vendor/node-api-headers/include/uv/tree.h +521 -0
- package/vendor/node-api-headers/include/uv/unix.h +512 -0
- package/vendor/node-api-headers/include/uv/version.h +43 -0
- package/vendor/node-api-headers/include/uv/win.h +698 -0
- package/vendor/node-api-headers/include/uv.h +1990 -0
- package/src/core/base/crc_gen.py +0 -109
|
@@ -1,23 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
-
// this software and associated documentation files (the “Software”), to deal in
|
|
5
|
-
// the Software without restriction, including without limitation the rights to use,
|
|
6
|
-
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
7
|
-
// Software, and to permit persons to whom the Software is furnished to do so,
|
|
8
|
-
// subject to the following conditions:
|
|
9
|
-
|
|
10
|
-
// The above copyright notice and this permission notice shall be included in all
|
|
11
|
-
// copies or substantial portions of the Software.
|
|
12
|
-
|
|
13
|
-
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
|
14
|
-
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
15
|
-
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
16
|
-
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
17
|
-
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
18
|
-
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
19
|
-
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
20
|
-
// OTHER DEALINGS IN THE SOFTWARE.
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
|
|
21
3
|
|
|
22
4
|
#include "base.hh"
|
|
23
5
|
#include "crc.inc"
|
|
@@ -115,6 +97,7 @@
|
|
|
115
97
|
#if defined(__linux__)
|
|
116
98
|
#include <sys/syscall.h>
|
|
117
99
|
#include <sys/sendfile.h>
|
|
100
|
+
#include <sys/eventfd.h>
|
|
118
101
|
#endif
|
|
119
102
|
#if defined(__APPLE__)
|
|
120
103
|
#include <sys/random.h>
|
|
@@ -932,6 +915,75 @@ Span<char> DuplicateString(Span<const char> str, Allocator *alloc)
|
|
|
932
915
|
return MakeSpan(new_str, str.len);
|
|
933
916
|
}
|
|
934
917
|
|
|
918
|
+
template <typename CompareFunc>
|
|
919
|
+
static inline int NaturalCmp(Span<const char> str1, Span<const char> str2, CompareFunc cmp)
|
|
920
|
+
{
|
|
921
|
+
Size i = 0;
|
|
922
|
+
Size j = 0;
|
|
923
|
+
|
|
924
|
+
while (i < str1.len && j < str2.len) {
|
|
925
|
+
int delta = cmp(str1[i], str2[j]);
|
|
926
|
+
|
|
927
|
+
if (delta) {
|
|
928
|
+
if (IsAsciiDigit(str1[i]) && IsAsciiDigit(str2[i])) {
|
|
929
|
+
while (i < str1.len && str1[i] == '0') {
|
|
930
|
+
i++;
|
|
931
|
+
}
|
|
932
|
+
while (j < str2.len && str2[j] == '0') {
|
|
933
|
+
j++;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
bool digit1 = false;
|
|
937
|
+
bool digit2 = false;
|
|
938
|
+
int bias = 0;
|
|
939
|
+
|
|
940
|
+
for (;;) {
|
|
941
|
+
digit1 = (i < str1.len) && IsAsciiDigit(str1[i]);
|
|
942
|
+
digit2 = (j < str2.len) && IsAsciiDigit(str2[j]);
|
|
943
|
+
|
|
944
|
+
if (!digit1 || !digit2)
|
|
945
|
+
break;
|
|
946
|
+
|
|
947
|
+
bias = bias ? bias : cmp(str1[i], str2[j]);
|
|
948
|
+
i++;
|
|
949
|
+
j++;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
if (!digit1 && !digit2 && bias) {
|
|
953
|
+
return bias;
|
|
954
|
+
} else if (digit1 || digit2) {
|
|
955
|
+
return digit1 ? 1 : -1;
|
|
956
|
+
}
|
|
957
|
+
} else {
|
|
958
|
+
return delta;
|
|
959
|
+
}
|
|
960
|
+
} else {
|
|
961
|
+
i++;
|
|
962
|
+
j++;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if (i == str1.len && j < str2.len) {
|
|
967
|
+
return -1;
|
|
968
|
+
} else if (i < str1.len) {
|
|
969
|
+
return 1;
|
|
970
|
+
} else {
|
|
971
|
+
return 0;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
int CmpNatural(Span<const char> str1, Span<const char> str2)
|
|
976
|
+
{
|
|
977
|
+
auto cmp = [](int a, int b) { return a - b; };
|
|
978
|
+
return NaturalCmp(str1, str2, cmp);
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
int CmpNaturalI(Span<const char> str1, Span<const char> str2)
|
|
982
|
+
{
|
|
983
|
+
auto cmp = [](int a, int b) { return LowerAscii(a) - LowerAscii(b); };
|
|
984
|
+
return NaturalCmp(str1, str2, cmp);
|
|
985
|
+
}
|
|
986
|
+
|
|
935
987
|
// ------------------------------------------------------------------------
|
|
936
988
|
// Format
|
|
937
989
|
// ------------------------------------------------------------------------
|
|
@@ -940,6 +992,8 @@ static const char DigitPairs[201] = "0001020304050607080910111213141516171819202
|
|
|
940
992
|
"25262728293031323334353637383940414243444546474849"
|
|
941
993
|
"50515253545556575859606162636465666768697071727374"
|
|
942
994
|
"75767778798081828384858687888990919293949596979899";
|
|
995
|
+
static const char BigHexLiterals[] = "0123456789ABCDEF";
|
|
996
|
+
static const char SmallHexLiterals[] = "0123456789abcdef";
|
|
943
997
|
|
|
944
998
|
static Span<char> FormatUnsignedToDecimal(uint64_t value, char out_buf[32])
|
|
945
999
|
{
|
|
@@ -975,13 +1029,11 @@ static Span<char> FormatUnsignedToBinary(uint64_t value, char out_buf[64])
|
|
|
975
1029
|
|
|
976
1030
|
static Span<char> FormatUnsignedToOctal(uint64_t value, char out_buf[64])
|
|
977
1031
|
{
|
|
978
|
-
static const char literals[] = "012345678";
|
|
979
|
-
|
|
980
1032
|
Size offset = 64;
|
|
981
1033
|
do {
|
|
982
1034
|
uint64_t digit = value & 0x7;
|
|
983
1035
|
value >>= 3;
|
|
984
|
-
out_buf[--offset] =
|
|
1036
|
+
out_buf[--offset] = BigHexLiterals[digit];
|
|
985
1037
|
} while (value);
|
|
986
1038
|
|
|
987
1039
|
return MakeSpan(out_buf + offset, 64 - offset);
|
|
@@ -989,13 +1041,11 @@ static Span<char> FormatUnsignedToOctal(uint64_t value, char out_buf[64])
|
|
|
989
1041
|
|
|
990
1042
|
static Span<char> FormatUnsignedToBigHex(uint64_t value, char out_buf[32])
|
|
991
1043
|
{
|
|
992
|
-
static const char literals[] = "0123456789ABCDEF";
|
|
993
|
-
|
|
994
1044
|
Size offset = 32;
|
|
995
1045
|
do {
|
|
996
1046
|
uint64_t digit = value & 0xF;
|
|
997
1047
|
value >>= 4;
|
|
998
|
-
out_buf[--offset] =
|
|
1048
|
+
out_buf[--offset] = BigHexLiterals[digit];
|
|
999
1049
|
} while (value);
|
|
1000
1050
|
|
|
1001
1051
|
return MakeSpan(out_buf + offset, 32 - offset);
|
|
@@ -1003,13 +1053,11 @@ static Span<char> FormatUnsignedToBigHex(uint64_t value, char out_buf[32])
|
|
|
1003
1053
|
|
|
1004
1054
|
static Span<char> FormatUnsignedToSmallHex(uint64_t value, char out_buf[32])
|
|
1005
1055
|
{
|
|
1006
|
-
static const char literals[] = "0123456789abcdef";
|
|
1007
|
-
|
|
1008
1056
|
Size offset = 32;
|
|
1009
1057
|
do {
|
|
1010
1058
|
uint64_t digit = value & 0xF;
|
|
1011
1059
|
value >>= 4;
|
|
1012
|
-
out_buf[--offset] =
|
|
1060
|
+
out_buf[--offset] = SmallHexLiterals[digit];
|
|
1013
1061
|
} while (value);
|
|
1014
1062
|
|
|
1015
1063
|
return MakeSpan(out_buf + offset, 32 - offset);
|
|
@@ -1185,406 +1233,429 @@ Span<const char> FormatFloatingPoint(T value, bool non_zero, int min_prec, int m
|
|
|
1185
1233
|
#endif
|
|
1186
1234
|
}
|
|
1187
1235
|
|
|
1236
|
+
template <typename AppendFunc>
|
|
1237
|
+
static inline void AppendPad(Size pad, char padding, AppendFunc append)
|
|
1238
|
+
{
|
|
1239
|
+
for (Size i = 0; i < pad; i++) {
|
|
1240
|
+
append(padding);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
template <typename AppendFunc>
|
|
1245
|
+
static inline void AppendSafe(char c, AppendFunc append)
|
|
1246
|
+
{
|
|
1247
|
+
if (IsAsciiControl(c))
|
|
1248
|
+
return;
|
|
1249
|
+
|
|
1250
|
+
append(c);
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1188
1253
|
template <typename AppendFunc>
|
|
1189
1254
|
static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
|
|
1190
1255
|
{
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
char num_buf[128];
|
|
1194
|
-
Span<const char> out = {};
|
|
1256
|
+
switch (arg.type) {
|
|
1257
|
+
case FmtType::Str: { append(arg.u.str); } break;
|
|
1195
1258
|
|
|
1196
|
-
|
|
1259
|
+
case FmtType::PadStr: {
|
|
1260
|
+
append(arg.u.str);
|
|
1261
|
+
AppendPad(arg.pad - arg.u.str.len, arg.padding, append);
|
|
1262
|
+
} break;
|
|
1263
|
+
case FmtType::RepeatStr: {
|
|
1264
|
+
Span<const char> str = arg.u.repeat.str;
|
|
1197
1265
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
case FmtType::Char: { out = MakeSpan(&arg.u.ch, 1); } break;
|
|
1266
|
+
for (int i = 0; i < arg.u.repeat.count; i++) {
|
|
1267
|
+
append(str);
|
|
1268
|
+
}
|
|
1269
|
+
} break;
|
|
1203
1270
|
|
|
1204
|
-
|
|
1271
|
+
case FmtType::Char: { append(MakeSpan(&arg.u.ch, 1)); } break;
|
|
1272
|
+
case FmtType::Buffer: {
|
|
1273
|
+
Span<const char> str = arg.u.buf;
|
|
1274
|
+
append(str);
|
|
1275
|
+
} break;
|
|
1276
|
+
case FmtType::Custom: { arg.u.custom.Format(append); } break;
|
|
1205
1277
|
|
|
1206
|
-
|
|
1207
|
-
if (arg.u.b) {
|
|
1208
|
-
out = "true";
|
|
1209
|
-
} else {
|
|
1210
|
-
out = "false";
|
|
1211
|
-
}
|
|
1212
|
-
} break;
|
|
1278
|
+
case FmtType::Bool: { append(arg.u.b ? "true" : "false"); } break;
|
|
1213
1279
|
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1280
|
+
case FmtType::Integer: {
|
|
1281
|
+
if (arg.u.i < 0) {
|
|
1282
|
+
char buf[128];
|
|
1283
|
+
Span<const char> str = FormatUnsignedToDecimal((uint64_t)-arg.u.i, buf);
|
|
1284
|
+
|
|
1285
|
+
if (arg.pad) {
|
|
1286
|
+
if (arg.padding == '0') {
|
|
1217
1287
|
append('-');
|
|
1288
|
+
AppendPad((Size)arg.pad - str.len - 1, arg.padding, append);
|
|
1218
1289
|
} else {
|
|
1219
|
-
|
|
1290
|
+
AppendPad((Size)arg.pad - str.len - 1, arg.padding, append);
|
|
1291
|
+
append('-');
|
|
1220
1292
|
}
|
|
1221
|
-
|
|
1222
|
-
out_buf.Append(FormatUnsignedToDecimal((uint64_t)-arg.u.i, num_buf));
|
|
1223
|
-
out = out_buf;
|
|
1224
1293
|
} else {
|
|
1225
|
-
|
|
1294
|
+
append('-');
|
|
1226
1295
|
}
|
|
1227
|
-
} break;
|
|
1228
|
-
case FmtType::Unsigned: {
|
|
1229
|
-
out = FormatUnsignedToDecimal(arg.u.u, num_buf);
|
|
1230
|
-
} break;
|
|
1231
|
-
case FmtType::Float: {
|
|
1232
|
-
static const uint32_t ExponentMask = 0x7f800000u;
|
|
1233
|
-
static const uint32_t MantissaMask = 0x007fffffu;
|
|
1234
|
-
static const uint32_t SignMask = 0x80000000u;
|
|
1235
1296
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1297
|
+
append(str);
|
|
1298
|
+
} else {
|
|
1299
|
+
char buf[128];
|
|
1300
|
+
Span<const char> str = FormatUnsignedToDecimal((uint64_t)arg.u.i, buf);
|
|
1238
1301
|
|
|
1239
|
-
|
|
1240
|
-
|
|
1302
|
+
AppendPad((Size)arg.pad - str.len, arg.padding, append);
|
|
1303
|
+
append(str);
|
|
1304
|
+
}
|
|
1305
|
+
} break;
|
|
1306
|
+
case FmtType::Unsigned: {
|
|
1307
|
+
char buf[128];
|
|
1308
|
+
Span<const char> str = FormatUnsignedToDecimal(arg.u.u, buf);
|
|
1241
1309
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
out = (u.u32 & SignMask) ? "-Inf" : "Inf";
|
|
1246
|
-
}
|
|
1247
|
-
} else {
|
|
1248
|
-
if (u.u32 & SignMask) {
|
|
1249
|
-
if (arg.pad_len < 0 && arg.pad_char == '0') {
|
|
1250
|
-
append('-');
|
|
1251
|
-
} else {
|
|
1252
|
-
out_buf.Append('-');
|
|
1253
|
-
}
|
|
1310
|
+
AppendPad((Size)arg.pad - str.len, arg.padding, append);
|
|
1311
|
+
append(str);
|
|
1312
|
+
} break;
|
|
1254
1313
|
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
} break;
|
|
1262
|
-
case FmtType::Double: {
|
|
1263
|
-
static const uint64_t ExponentMask = 0x7FF0000000000000ull;
|
|
1264
|
-
static const uint64_t MantissaMask = 0x000FFFFFFFFFFFFFull;
|
|
1265
|
-
static const uint64_t SignMask = 0x8000000000000000ull;
|
|
1314
|
+
case FmtType::Float: {
|
|
1315
|
+
static const uint32_t ExponentMask = 0x7f800000u;
|
|
1316
|
+
static const uint32_t MantissaMask = 0x007fffffu;
|
|
1317
|
+
static const uint32_t SignMask = 0x80000000u;
|
|
1266
1318
|
|
|
1267
|
-
|
|
1268
|
-
|
|
1319
|
+
union { float f; uint32_t u32; } u;
|
|
1320
|
+
u.f = arg.u.f.value;
|
|
1269
1321
|
|
|
1270
|
-
|
|
1271
|
-
|
|
1322
|
+
if ((u.u32 & ExponentMask) == ExponentMask) {
|
|
1323
|
+
uint32_t mantissa = u.u32 & MantissaMask;
|
|
1272
1324
|
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
} else {
|
|
1276
|
-
out = (u.u64 & SignMask) ? "-Inf" : "Inf";
|
|
1277
|
-
}
|
|
1325
|
+
if (mantissa) {
|
|
1326
|
+
append("NaN");
|
|
1278
1327
|
} else {
|
|
1279
|
-
|
|
1280
|
-
if (arg.pad_len < 0 && arg.pad_char == '0') {
|
|
1281
|
-
append('-');
|
|
1282
|
-
} else {
|
|
1283
|
-
out_buf.Append('-');
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
out_buf.Append(FormatFloatingPoint(-u.d, true, arg.u.d.min_prec, arg.u.d.max_prec, num_buf));
|
|
1287
|
-
out = out_buf;
|
|
1288
|
-
} else {
|
|
1289
|
-
out = FormatFloatingPoint(u.d, u.u64, arg.u.d.min_prec, arg.u.d.max_prec, num_buf);
|
|
1290
|
-
}
|
|
1328
|
+
append((u.u32 & SignMask) ? "-Inf" : "Inf");
|
|
1291
1329
|
}
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
out = FormatUnsignedToBinary(arg.u.u, num_buf);
|
|
1295
|
-
} break;
|
|
1296
|
-
case FmtType::Octal: {
|
|
1297
|
-
out = FormatUnsignedToOctal(arg.u.u, num_buf);
|
|
1298
|
-
} break;
|
|
1299
|
-
case FmtType::BigHex: {
|
|
1300
|
-
out = FormatUnsignedToBigHex(arg.u.u, num_buf);
|
|
1301
|
-
} break;
|
|
1302
|
-
case FmtType::SmallHex: {
|
|
1303
|
-
out = FormatUnsignedToSmallHex(arg.u.u, num_buf);
|
|
1304
|
-
} break;
|
|
1330
|
+
} else {
|
|
1331
|
+
char buf[128];
|
|
1305
1332
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
size = (double)-arg.u.i;
|
|
1310
|
-
if (arg.pad_len < 0 && arg.pad_char == '0') {
|
|
1311
|
-
append('-');
|
|
1312
|
-
} else {
|
|
1313
|
-
out_buf.Append('-');
|
|
1314
|
-
}
|
|
1333
|
+
if (u.u32 & SignMask) {
|
|
1334
|
+
append('-');
|
|
1335
|
+
append(FormatFloatingPoint(-u.f, true, arg.u.f.min_prec, arg.u.f.max_prec, buf));
|
|
1315
1336
|
} else {
|
|
1316
|
-
|
|
1337
|
+
append(FormatFloatingPoint(u.f, u.u32, arg.u.f.min_prec, arg.u.f.max_prec, buf));
|
|
1317
1338
|
}
|
|
1339
|
+
}
|
|
1340
|
+
} break;
|
|
1341
|
+
case FmtType::Double: {
|
|
1342
|
+
static const uint64_t ExponentMask = 0x7FF0000000000000ull;
|
|
1343
|
+
static const uint64_t MantissaMask = 0x000FFFFFFFFFFFFFull;
|
|
1344
|
+
static const uint64_t SignMask = 0x8000000000000000ull;
|
|
1318
1345
|
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
int prec = 1 + (size < 9.9995) + (size < 99.995);
|
|
1323
|
-
out_buf.Append(FormatFloatingPoint(size, true, prec, prec, num_buf));
|
|
1324
|
-
out_buf.Append(" GiB");
|
|
1325
|
-
} else if (size >= 1048524.0) {
|
|
1326
|
-
size /= 1048576.0;
|
|
1346
|
+
union { double d; uint64_t u64; } u;
|
|
1347
|
+
u.d = arg.u.d.value;
|
|
1327
1348
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
out_buf.Append(" MiB");
|
|
1331
|
-
} else if (size >= 1023.95) {
|
|
1332
|
-
size /= 1024.0;
|
|
1349
|
+
if ((u.u64 & ExponentMask) == ExponentMask) {
|
|
1350
|
+
uint64_t mantissa = u.u64 & MantissaMask;
|
|
1333
1351
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
out_buf.Append(" kiB");
|
|
1352
|
+
if (mantissa) {
|
|
1353
|
+
append("NaN");
|
|
1337
1354
|
} else {
|
|
1338
|
-
|
|
1339
|
-
out_buf.Append(" B");
|
|
1355
|
+
append((u.u64 & SignMask) ? "-Inf" : "Inf");
|
|
1340
1356
|
}
|
|
1357
|
+
} else {
|
|
1358
|
+
char buf[128];
|
|
1341
1359
|
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
double size;
|
|
1346
|
-
if (arg.u.i < 0) {
|
|
1347
|
-
size = (double)-arg.u.i;
|
|
1348
|
-
if (arg.pad_len < 0 && arg.pad_char == '0') {
|
|
1349
|
-
append('-');
|
|
1350
|
-
} else {
|
|
1351
|
-
out_buf.Append('-');
|
|
1352
|
-
}
|
|
1360
|
+
if (u.u64 & SignMask) {
|
|
1361
|
+
append('-');
|
|
1362
|
+
append(FormatFloatingPoint(-u.d, true, arg.u.d.min_prec, arg.u.d.max_prec, buf));
|
|
1353
1363
|
} else {
|
|
1354
|
-
|
|
1364
|
+
append(FormatFloatingPoint(u.d, u.u64, arg.u.d.min_prec, arg.u.d.max_prec, buf));
|
|
1355
1365
|
}
|
|
1366
|
+
}
|
|
1367
|
+
} break;
|
|
1356
1368
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1369
|
+
case FmtType::Binary: {
|
|
1370
|
+
char buf[128];
|
|
1371
|
+
Span<const char> str = FormatUnsignedToBinary(arg.u.u, buf);
|
|
1359
1372
|
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1373
|
+
AppendPad((Size)arg.pad - str.len, arg.padding, append);
|
|
1374
|
+
append(str);
|
|
1375
|
+
} break;
|
|
1376
|
+
case FmtType::Octal: {
|
|
1377
|
+
char buf[128];
|
|
1378
|
+
Span<const char> str = FormatUnsignedToOctal(arg.u.u, buf);
|
|
1365
1379
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1380
|
+
AppendPad((Size)arg.pad - str.len, arg.padding, append);
|
|
1381
|
+
append(str);
|
|
1382
|
+
} break;
|
|
1383
|
+
case FmtType::BigHex: {
|
|
1384
|
+
char buf[128];
|
|
1385
|
+
Span<const char> str = FormatUnsignedToBigHex(arg.u.u, buf);
|
|
1371
1386
|
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
}
|
|
1387
|
+
AppendPad((Size)arg.pad - str.len, arg.padding, append);
|
|
1388
|
+
append(str);
|
|
1389
|
+
} break;
|
|
1390
|
+
case FmtType::SmallHex: {
|
|
1391
|
+
char buf[128];
|
|
1392
|
+
Span<const char> str = FormatUnsignedToSmallHex(arg.u.u, buf);
|
|
1379
1393
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1394
|
+
AppendPad((Size)arg.pad - str.len, arg.padding, append);
|
|
1395
|
+
append(str);
|
|
1396
|
+
} break;
|
|
1382
1397
|
|
|
1383
|
-
|
|
1384
|
-
|
|
1398
|
+
case FmtType::BigBytes: {
|
|
1399
|
+
for (uint8_t c: arg.u.hex) {
|
|
1400
|
+
char encoded[2];
|
|
1385
1401
|
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
out_buf.Append('-');
|
|
1389
|
-
year = -year;
|
|
1390
|
-
}
|
|
1391
|
-
if (year < 10) {
|
|
1392
|
-
out_buf.Append("000");
|
|
1393
|
-
} else if (year < 100) {
|
|
1394
|
-
out_buf.Append("00");
|
|
1395
|
-
} else if (year < 1000) {
|
|
1396
|
-
out_buf.Append('0');
|
|
1397
|
-
}
|
|
1398
|
-
out_buf.Append(FormatUnsignedToDecimal((uint64_t)year, num_buf));
|
|
1399
|
-
out_buf.Append('-');
|
|
1400
|
-
if (arg.u.date.st.month < 10) {
|
|
1401
|
-
out_buf.Append('0');
|
|
1402
|
-
}
|
|
1403
|
-
out_buf.Append(FormatUnsignedToDecimal((uint64_t)arg.u.date.st.month, num_buf));
|
|
1404
|
-
out_buf.Append('-');
|
|
1405
|
-
if (arg.u.date.st.day < 10) {
|
|
1406
|
-
out_buf.Append('0');
|
|
1407
|
-
}
|
|
1408
|
-
out_buf.Append(FormatUnsignedToDecimal((uint64_t)arg.u.date.st.day, num_buf));
|
|
1409
|
-
out = out_buf;
|
|
1410
|
-
} break;
|
|
1402
|
+
encoded[0] = BigHexLiterals[((uint8_t)c >> 4) & 0xF];
|
|
1403
|
+
encoded[1] = BigHexLiterals[((uint8_t)c >> 0) & 0xF];
|
|
1411
1404
|
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
FmtArg(spec.min).Pad0(-2), FmtArg(spec.sec).Pad0(-2), FmtArg(spec.msec).Pad0(-3),
|
|
1423
|
-
offset_h >= 0 ? "+" : "", FmtArg(offset_h).Pad0(-2), FmtArg(offset_m).Pad0(-2)).len;
|
|
1424
|
-
} else if (spec.offset) {
|
|
1425
|
-
int offset_h = spec.offset / 60;
|
|
1426
|
-
int offset_m = spec.offset % 60;
|
|
1427
|
-
|
|
1428
|
-
out_buf.len = Fmt(out_buf.data, "%1%2%3T%4%5%6%7%8%9",
|
|
1429
|
-
FmtArg(spec.year).Pad0(-2), FmtArg(spec.month).Pad0(-2),
|
|
1430
|
-
FmtArg(spec.day).Pad0(-2), FmtArg(spec.hour).Pad0(-2),
|
|
1431
|
-
FmtArg(spec.min).Pad0(-2), FmtArg(spec.sec).Pad0(-2),
|
|
1432
|
-
offset_h >= 0 ? "+" : "", FmtArg(offset_h).Pad0(-2), FmtArg(offset_m).Pad0(-2)).len;
|
|
1433
|
-
} else if (arg.u.time.ms) {
|
|
1434
|
-
out_buf.len = Fmt(out_buf.data, "%1%2%3T%4%5%6.%7Z",
|
|
1435
|
-
FmtArg(spec.year).Pad0(-2), FmtArg(spec.month).Pad0(-2),
|
|
1436
|
-
FmtArg(spec.day).Pad0(-2), FmtArg(spec.hour).Pad0(-2),
|
|
1437
|
-
FmtArg(spec.min).Pad0(-2), FmtArg(spec.sec).Pad0(-2), FmtArg(spec.msec).Pad0(-3)).len;
|
|
1438
|
-
} else {
|
|
1439
|
-
out_buf.len = Fmt(out_buf.data, "%1%2%3T%4%5%6Z",
|
|
1440
|
-
FmtArg(spec.year).Pad0(-2), FmtArg(spec.month).Pad0(-2),
|
|
1441
|
-
FmtArg(spec.day).Pad0(-2), FmtArg(spec.hour).Pad0(-2),
|
|
1442
|
-
FmtArg(spec.min).Pad0(-2), FmtArg(spec.sec).Pad0(-2)).len;
|
|
1443
|
-
}
|
|
1444
|
-
out = out_buf;
|
|
1445
|
-
} break;
|
|
1446
|
-
case FmtType::TimeNice: {
|
|
1447
|
-
const TimeSpec &spec = arg.u.time.spec;
|
|
1405
|
+
Span<const char> buf = MakeSpan(encoded, 2);
|
|
1406
|
+
append(buf);
|
|
1407
|
+
}
|
|
1408
|
+
} break;
|
|
1409
|
+
case FmtType::SmallBytes: {
|
|
1410
|
+
for (uint8_t c: arg.u.hex) {
|
|
1411
|
+
char encoded[2];
|
|
1412
|
+
|
|
1413
|
+
encoded[0] = SmallHexLiterals[((uint8_t)c >> 4) & 0xF];
|
|
1414
|
+
encoded[1] = SmallHexLiterals[((uint8_t)c >> 0) & 0xF];
|
|
1448
1415
|
|
|
1416
|
+
Span<const char> buf = MakeSpan(encoded, 2);
|
|
1417
|
+
append(buf);
|
|
1418
|
+
}
|
|
1419
|
+
} break;
|
|
1420
|
+
|
|
1421
|
+
case FmtType::MemorySize: {
|
|
1422
|
+
char buf[128];
|
|
1423
|
+
|
|
1424
|
+
double size;
|
|
1425
|
+
if (arg.u.i < 0) {
|
|
1426
|
+
append('-');
|
|
1427
|
+
size = (double)-arg.u.i;
|
|
1428
|
+
} else {
|
|
1429
|
+
size = (double)arg.u.i;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
if (size >= 1073688137.0) {
|
|
1433
|
+
size /= 1073741824.0;
|
|
1434
|
+
|
|
1435
|
+
int prec = 1 + (size < 9.9995) + (size < 99.995);
|
|
1436
|
+
append(FormatFloatingPoint(size, true, prec, prec, buf));
|
|
1437
|
+
append(" GiB");
|
|
1438
|
+
} else if (size >= 1048524.0) {
|
|
1439
|
+
size /= 1048576.0;
|
|
1440
|
+
|
|
1441
|
+
int prec = 1 + (size < 9.9995) + (size < 99.995);
|
|
1442
|
+
append(FormatFloatingPoint(size, true, prec, prec, buf));
|
|
1443
|
+
append(" MiB");
|
|
1444
|
+
} else if (size >= 1023.95) {
|
|
1445
|
+
size /= 1024.0;
|
|
1446
|
+
|
|
1447
|
+
int prec = 1 + (size < 9.9995) + (size < 99.995);
|
|
1448
|
+
append(FormatFloatingPoint(size, true, prec, prec, buf));
|
|
1449
|
+
append(" kiB");
|
|
1450
|
+
} else {
|
|
1451
|
+
append(FormatFloatingPoint(size, arg.u.i, 0, 0, buf));
|
|
1452
|
+
append(" B");
|
|
1453
|
+
}
|
|
1454
|
+
} break;
|
|
1455
|
+
case FmtType::DiskSize: {
|
|
1456
|
+
char buf[128];
|
|
1457
|
+
|
|
1458
|
+
double size;
|
|
1459
|
+
if (arg.u.i < 0) {
|
|
1460
|
+
append('-');
|
|
1461
|
+
size = (double)-arg.u.i;
|
|
1462
|
+
} else {
|
|
1463
|
+
size = (double)arg.u.i;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
if (size >= 999950000.0) {
|
|
1467
|
+
size /= 1000000000.0;
|
|
1468
|
+
|
|
1469
|
+
int prec = 1 + (size < 9.9995) + (size < 99.995);
|
|
1470
|
+
append(FormatFloatingPoint(size, true, prec, prec, buf));
|
|
1471
|
+
append(" GB");
|
|
1472
|
+
} else if (size >= 999950.0) {
|
|
1473
|
+
size /= 1000000.0;
|
|
1474
|
+
|
|
1475
|
+
int prec = 1 + (size < 9.9995) + (size < 99.995);
|
|
1476
|
+
append(FormatFloatingPoint(size, true, prec, prec, buf));
|
|
1477
|
+
append(" MB");
|
|
1478
|
+
} else if (size >= 999.95) {
|
|
1479
|
+
size /= 1000.0;
|
|
1480
|
+
|
|
1481
|
+
int prec = 1 + (size < 9.9995) + (size < 99.995);
|
|
1482
|
+
append(FormatFloatingPoint(size, true, prec, prec, buf));
|
|
1483
|
+
append(" kB");
|
|
1484
|
+
} else {
|
|
1485
|
+
append(FormatFloatingPoint(size, arg.u.i, 0, 0, buf));
|
|
1486
|
+
append(" B");
|
|
1487
|
+
}
|
|
1488
|
+
} break;
|
|
1489
|
+
|
|
1490
|
+
case FmtType::Date: {
|
|
1491
|
+
K_ASSERT(!arg.u.date.value || arg.u.date.IsValid());
|
|
1492
|
+
|
|
1493
|
+
char buf[128];
|
|
1494
|
+
|
|
1495
|
+
int year = arg.u.date.st.year;
|
|
1496
|
+
if (year < 0) {
|
|
1497
|
+
append('-');
|
|
1498
|
+
year = -year;
|
|
1499
|
+
}
|
|
1500
|
+
if (year < 10) {
|
|
1501
|
+
append("000");
|
|
1502
|
+
} else if (year < 100) {
|
|
1503
|
+
append("00");
|
|
1504
|
+
} else if (year < 1000) {
|
|
1505
|
+
append('0');
|
|
1506
|
+
}
|
|
1507
|
+
append(FormatUnsignedToDecimal((uint64_t)year, buf));
|
|
1508
|
+
append('-');
|
|
1509
|
+
if (arg.u.date.st.month < 10) {
|
|
1510
|
+
append('0');
|
|
1511
|
+
}
|
|
1512
|
+
append(FormatUnsignedToDecimal((uint64_t)arg.u.date.st.month, buf));
|
|
1513
|
+
append('-');
|
|
1514
|
+
if (arg.u.date.st.day < 10) {
|
|
1515
|
+
append('0');
|
|
1516
|
+
}
|
|
1517
|
+
append(FormatUnsignedToDecimal((uint64_t)arg.u.date.st.day, buf));
|
|
1518
|
+
} break;
|
|
1519
|
+
|
|
1520
|
+
case FmtType::TimeISO: {
|
|
1521
|
+
const TimeSpec &spec = arg.u.time.spec;
|
|
1522
|
+
|
|
1523
|
+
LocalArray<char, 128> buf;
|
|
1524
|
+
|
|
1525
|
+
if (spec.offset && arg.u.time.ms) {
|
|
1449
1526
|
int offset_h = spec.offset / 60;
|
|
1450
1527
|
int offset_m = spec.offset % 60;
|
|
1451
1528
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
FmtArg(spec.year).Pad0(-2), FmtArg(spec.month).Pad0(-2),
|
|
1461
|
-
FmtArg(spec.day).Pad0(-2), FmtArg(spec.hour).Pad0(-2),
|
|
1462
|
-
FmtArg(spec.min).Pad0(-2), FmtArg(spec.sec).Pad0(-2),
|
|
1463
|
-
offset_h >= 0 ? "+" : "", FmtArg(offset_h).Pad0(-2), FmtArg(offset_m).Pad0(-2)).len;
|
|
1464
|
-
}
|
|
1465
|
-
out = out_buf;
|
|
1466
|
-
} break;
|
|
1529
|
+
buf.len = Fmt(buf.data, "%1%2%3T%4%5%6.%7%8%9%10",
|
|
1530
|
+
FmtInt(spec.year, 2), FmtInt(spec.month, 2),
|
|
1531
|
+
FmtInt(spec.day, 2), FmtInt(spec.hour, 2),
|
|
1532
|
+
FmtInt(spec.min, 2), FmtInt(spec.sec, 2), FmtInt(spec.msec, 3),
|
|
1533
|
+
offset_h >= 0 ? "+" : "", FmtInt(offset_h, 2), FmtInt(offset_m, 2)).len;
|
|
1534
|
+
} else if (spec.offset) {
|
|
1535
|
+
int offset_h = spec.offset / 60;
|
|
1536
|
+
int offset_m = spec.offset % 60;
|
|
1467
1537
|
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1538
|
+
buf.len = Fmt(buf.data, "%1%2%3T%4%5%6%7%8%9",
|
|
1539
|
+
FmtInt(spec.year, 2), FmtInt(spec.month, 2),
|
|
1540
|
+
FmtInt(spec.day, 2), FmtInt(spec.hour, 2),
|
|
1541
|
+
FmtInt(spec.min, 2), FmtInt(spec.sec, 2),
|
|
1542
|
+
offset_h >= 0 ? "+" : "", FmtInt(offset_h, 2), FmtInt(offset_m, 2)).len;
|
|
1543
|
+
} else if (arg.u.time.ms) {
|
|
1544
|
+
buf.len = Fmt(buf.data, "%1%2%3T%4%5%6.%7Z",
|
|
1545
|
+
FmtInt(spec.year, 2), FmtInt(spec.month, 2),
|
|
1546
|
+
FmtInt(spec.day, 2), FmtInt(spec.hour, 2),
|
|
1547
|
+
FmtInt(spec.min, 2), FmtInt(spec.sec, 2), FmtInt(spec.msec, 3)).len;
|
|
1548
|
+
} else {
|
|
1549
|
+
buf.len = Fmt(buf.data, "%1%2%3T%4%5%6Z",
|
|
1550
|
+
FmtInt(spec.year, 2), FmtInt(spec.month, 2),
|
|
1551
|
+
FmtInt(spec.day, 2), FmtInt(spec.hour, 2),
|
|
1552
|
+
FmtInt(spec.min, 2), FmtInt(spec.sec, 2)).len;
|
|
1553
|
+
}
|
|
1471
1554
|
|
|
1472
|
-
|
|
1555
|
+
append(buf);
|
|
1556
|
+
} break;
|
|
1557
|
+
case FmtType::TimeNice: {
|
|
1558
|
+
const TimeSpec &spec = arg.u.time.spec;
|
|
1473
1559
|
|
|
1474
|
-
|
|
1475
|
-
int rnd = GetRandomInt(0, (int)chars.len);
|
|
1476
|
-
out_buf.Append(chars[rnd]);
|
|
1477
|
-
}
|
|
1560
|
+
LocalArray<char, 128> buf;
|
|
1478
1561
|
|
|
1479
|
-
|
|
1480
|
-
|
|
1562
|
+
if (arg.u.time.ms) {
|
|
1563
|
+
int offset_h = spec.offset / 60;
|
|
1564
|
+
int offset_m = spec.offset % 60;
|
|
1481
1565
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1566
|
+
buf.len = Fmt(buf.data, "%1-%2-%3 %4:%5:%6.%7 %8%9%10",
|
|
1567
|
+
FmtInt(spec.year, 2), FmtInt(spec.month, 2),
|
|
1568
|
+
FmtInt(spec.day, 2), FmtInt(spec.hour, 2),
|
|
1569
|
+
FmtInt(spec.min, 2), FmtInt(spec.sec, 2), FmtInt(spec.msec, 3),
|
|
1570
|
+
offset_h >= 0 ? "+" : "", FmtInt(offset_h, 2), FmtInt(offset_m, 2)).len;
|
|
1571
|
+
} else {
|
|
1572
|
+
int offset_h = spec.offset / 60;
|
|
1573
|
+
int offset_m = spec.offset % 60;
|
|
1574
|
+
|
|
1575
|
+
buf.len = Fmt(buf.data, "%1-%2-%3 %4:%5:%6 %7%8%9",
|
|
1576
|
+
FmtInt(spec.year, 2), FmtInt(spec.month, 2),
|
|
1577
|
+
FmtInt(spec.day, 2), FmtInt(spec.hour, 2),
|
|
1578
|
+
FmtInt(spec.min, 2), FmtInt(spec.sec, 2),
|
|
1579
|
+
offset_h >= 0 ? "+" : "", FmtInt(offset_h, 2), FmtInt(offset_m, 2)).len;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
append(buf);
|
|
1583
|
+
} break;
|
|
1584
|
+
|
|
1585
|
+
case FmtType::List: {
|
|
1586
|
+
Span<const char> separator = arg.u.list.separator;
|
|
1587
|
+
|
|
1588
|
+
if (arg.u.list.u.names.len) {
|
|
1589
|
+
append(arg.u.list.u.names[0]);
|
|
1590
|
+
|
|
1591
|
+
for (Size i = 1; i < arg.u.list.u.names.len; i++) {
|
|
1592
|
+
append(separator);
|
|
1593
|
+
append(arg.u.list.u.names[i]);
|
|
1494
1594
|
}
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1595
|
+
} else {
|
|
1596
|
+
append(T("None"));
|
|
1597
|
+
}
|
|
1598
|
+
} break;
|
|
1599
|
+
case FmtType::FlagNames: {
|
|
1600
|
+
uint64_t flags = arg.u.list.flags;
|
|
1601
|
+
Span<const char> separator = arg.u.list.separator;
|
|
1602
|
+
|
|
1603
|
+
if (flags) {
|
|
1604
|
+
for (;;) {
|
|
1605
|
+
int idx = CountTrailingZeros(flags);
|
|
1606
|
+
flags &= ~(1ull << idx);
|
|
1607
|
+
|
|
1608
|
+
append(arg.u.list.u.names[idx]);
|
|
1609
|
+
if (!flags)
|
|
1610
|
+
break;
|
|
1611
|
+
append(separator);
|
|
1508
1612
|
}
|
|
1509
|
-
}
|
|
1613
|
+
} else {
|
|
1614
|
+
append(T("None"));
|
|
1615
|
+
}
|
|
1616
|
+
} break;
|
|
1617
|
+
case FmtType::FlagOptions: {
|
|
1618
|
+
uint64_t flags = arg.u.list.flags;
|
|
1619
|
+
Span<const char> separator = arg.u.list.separator;
|
|
1510
1620
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
arg2.pad_len = arg.pad_len;
|
|
1516
|
-
arg2.pad_char = arg.pad_char;
|
|
1517
|
-
|
|
1518
|
-
const uint8_t *ptr = (const uint8_t *)arg.u.span.ptr;
|
|
1519
|
-
for (Size j = 0; j < arg.u.span.len; j++) {
|
|
1520
|
-
switch (arg.u.span.type) {
|
|
1521
|
-
case FmtType::Str1: { arg2.u.str1 = *(const char **)ptr; } break;
|
|
1522
|
-
case FmtType::Str2: { arg2.u.str2 = *(const Span<const char> *)ptr; } break;
|
|
1523
|
-
case FmtType::Buffer: { K_UNREACHABLE(); } break;
|
|
1524
|
-
case FmtType::Char: { arg2.u.ch = *(const char *)ptr; } break;
|
|
1525
|
-
case FmtType::Custom: { K_UNREACHABLE(); } break;
|
|
1526
|
-
case FmtType::Bool: { arg2.u.b = *(const bool *)ptr; } break;
|
|
1527
|
-
case FmtType::Integer:
|
|
1528
|
-
case FmtType::Unsigned:
|
|
1529
|
-
case FmtType::Binary:
|
|
1530
|
-
case FmtType::Octal:
|
|
1531
|
-
case FmtType::BigHex:
|
|
1532
|
-
case FmtType::SmallHex: {
|
|
1533
|
-
switch (arg.u.span.type_len) {
|
|
1534
|
-
case 8: { arg2.u.u = *(const uint64_t *)ptr; } break;
|
|
1535
|
-
case 4: { arg2.u.u = *(const uint32_t *)ptr; } break;
|
|
1536
|
-
case 2: { arg2.u.u = *(const uint16_t *)ptr; } break;
|
|
1537
|
-
case 1: { arg2.u.u = *(const uint8_t *)ptr; } break;
|
|
1538
|
-
default: { K_UNREACHABLE(); } break;
|
|
1539
|
-
}
|
|
1540
|
-
} break;
|
|
1541
|
-
case FmtType::Float: {
|
|
1542
|
-
arg2.u.f.value = *(const float *)ptr;
|
|
1543
|
-
arg2.u.d.min_prec = 0;
|
|
1544
|
-
arg2.u.d.max_prec = INT_MAX;
|
|
1545
|
-
} break;
|
|
1546
|
-
case FmtType::Double: {
|
|
1547
|
-
arg2.u.d.value = *(const double *)ptr;
|
|
1548
|
-
arg2.u.d.min_prec = 0;
|
|
1549
|
-
arg2.u.d.max_prec = INT_MAX;
|
|
1550
|
-
} break;
|
|
1551
|
-
case FmtType::MemorySize:
|
|
1552
|
-
case FmtType::DiskSize: { arg2.u.i = *(const int64_t *)ptr; } break;
|
|
1553
|
-
case FmtType::Date: { arg2.u.date = *(const LocalDate *)ptr; } break;
|
|
1554
|
-
case FmtType::TimeISO:
|
|
1555
|
-
case FmtType::TimeNice: { arg2.u.time = *(decltype(FmtArg::u.time) *)ptr; } break;
|
|
1556
|
-
case FmtType::Random: { K_UNREACHABLE(); } break;
|
|
1557
|
-
case FmtType::FlagNames: { K_UNREACHABLE(); } break;
|
|
1558
|
-
case FmtType::FlagOptions: { K_UNREACHABLE(); } break;
|
|
1559
|
-
case FmtType::Span: { K_UNREACHABLE(); } break;
|
|
1560
|
-
}
|
|
1561
|
-
ptr += arg.u.span.type_len;
|
|
1621
|
+
if (arg.u.list.flags) {
|
|
1622
|
+
for (;;) {
|
|
1623
|
+
int idx = CountTrailingZeros(flags);
|
|
1624
|
+
flags &= ~(1ull << idx);
|
|
1562
1625
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1626
|
+
append(arg.u.list.u.options[idx].name);
|
|
1627
|
+
if (!flags)
|
|
1628
|
+
break;
|
|
1629
|
+
append(separator);
|
|
1567
1630
|
}
|
|
1631
|
+
} else {
|
|
1632
|
+
append(T("None"));
|
|
1633
|
+
}
|
|
1634
|
+
} break;
|
|
1568
1635
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1636
|
+
case FmtType::Random: {
|
|
1637
|
+
LocalArray<char, 512> buf;
|
|
1638
|
+
|
|
1639
|
+
static const char *const DefaultChars = "abcdefghijklmnopqrstuvwxyz0123456789";
|
|
1640
|
+
Span<const char> chars = arg.u.random.chars ? arg.u.random.chars : DefaultChars;
|
|
1641
|
+
|
|
1642
|
+
K_ASSERT(arg.u.random.len <= K_SIZE(buf.data));
|
|
1643
|
+
buf.len = arg.u.random.len;
|
|
1572
1644
|
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
append(arg.pad_char);
|
|
1645
|
+
for (Size j = 0; j < arg.u.random.len; j++) {
|
|
1646
|
+
int rnd = GetRandomInt(0, (int)chars.len);
|
|
1647
|
+
buf[j] = chars[rnd];
|
|
1577
1648
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1649
|
+
|
|
1650
|
+
append(buf);
|
|
1651
|
+
} break;
|
|
1652
|
+
|
|
1653
|
+
case FmtType::SafeStr: {
|
|
1654
|
+
for (char c: arg.u.str) {
|
|
1655
|
+
AppendSafe(c, append);
|
|
1584
1656
|
}
|
|
1585
|
-
}
|
|
1586
|
-
|
|
1587
|
-
}
|
|
1657
|
+
} break;
|
|
1658
|
+
case FmtType::SafeChar: { AppendSafe(arg.u.ch, append); } break;
|
|
1588
1659
|
}
|
|
1589
1660
|
}
|
|
1590
1661
|
|
|
@@ -1864,17 +1935,48 @@ void FmtLowerAscii::Format(FunctionRef<void(Span<const char>)> append) const
|
|
|
1864
1935
|
}
|
|
1865
1936
|
}
|
|
1866
1937
|
|
|
1938
|
+
void FmtUrlSafe::Format(FunctionRef<void(Span<const char>)> append) const
|
|
1939
|
+
{
|
|
1940
|
+
for (char c: str) {
|
|
1941
|
+
if (IsAsciiAlphaOrDigit(c) || strchr(passthrough, c)) {
|
|
1942
|
+
append((char)c);
|
|
1943
|
+
} else {
|
|
1944
|
+
char encoded[3];
|
|
1945
|
+
|
|
1946
|
+
encoded[0] = '%';
|
|
1947
|
+
encoded[1] = BigHexLiterals[((uint8_t)c >> 4) & 0xF];
|
|
1948
|
+
encoded[2] = BigHexLiterals[((uint8_t)c >> 0) & 0xF];
|
|
1949
|
+
|
|
1950
|
+
Span<const char> buf = MakeSpan(encoded, 3);
|
|
1951
|
+
append(buf);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
void FmtHtmlSafe::Format(FunctionRef<void(Span<const char>)> append) const
|
|
1957
|
+
{
|
|
1958
|
+
for (char c: str) {
|
|
1959
|
+
switch (c) {
|
|
1960
|
+
case '<': { append("<"); } break;
|
|
1961
|
+
case '>': { append(">"); } break;
|
|
1962
|
+
case '"': { append("""); } break;
|
|
1963
|
+
case '\'': { append("'"); } break;
|
|
1964
|
+
case '&': { append("&"); } break;
|
|
1965
|
+
|
|
1966
|
+
default: { append(c); } break;
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1867
1971
|
void FmtEscape::Format(FunctionRef<void(Span<const char>)> append) const
|
|
1868
1972
|
{
|
|
1869
1973
|
for (char c: str) {
|
|
1870
|
-
if (c == '
|
|
1871
|
-
append("\\\"");
|
|
1872
|
-
} else if (c == '\'') {
|
|
1873
|
-
append("\\'");
|
|
1874
|
-
} else if (c == '\r') {
|
|
1974
|
+
if (c == '\r') {
|
|
1875
1975
|
append("\\r");
|
|
1876
1976
|
} else if (c == '\n') {
|
|
1877
1977
|
append("\\n");
|
|
1978
|
+
} else if (c == '\\') {
|
|
1979
|
+
append("\\\\");
|
|
1878
1980
|
} else if ((unsigned int)c < 32) {
|
|
1879
1981
|
char encoded[4];
|
|
1880
1982
|
|
|
@@ -1885,32 +1987,15 @@ void FmtEscape::Format(FunctionRef<void(Span<const char>)> append) const
|
|
|
1885
1987
|
|
|
1886
1988
|
Span<const char> buf = MakeSpan(encoded, 4);
|
|
1887
1989
|
append(buf);
|
|
1990
|
+
} else if (c == quote) {
|
|
1991
|
+
append('\\');
|
|
1992
|
+
append(quote);
|
|
1888
1993
|
} else {
|
|
1889
1994
|
append(c);
|
|
1890
1995
|
}
|
|
1891
1996
|
}
|
|
1892
1997
|
}
|
|
1893
1998
|
|
|
1894
|
-
void FmtUrlSafe::Format(FunctionRef<void(Span<const char>)> append) const
|
|
1895
|
-
{
|
|
1896
|
-
static const char literals[] = "0123456789ABCDEF";
|
|
1897
|
-
|
|
1898
|
-
for (char c: str) {
|
|
1899
|
-
if (IsAsciiAlphaOrDigit(c) || strchr(passthrough, c)) {
|
|
1900
|
-
append((char)c);
|
|
1901
|
-
} else {
|
|
1902
|
-
char encoded[3];
|
|
1903
|
-
|
|
1904
|
-
encoded[0] = '%';
|
|
1905
|
-
encoded[1] = literals[((uint8_t)c >> 4) & 0xF];
|
|
1906
|
-
encoded[2] = literals[((uint8_t)c >> 0) & 0xF];
|
|
1907
|
-
|
|
1908
|
-
Span<const char> buf = MakeSpan(encoded, 3);
|
|
1909
|
-
append(buf);
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
1999
|
FmtArg FmtVersion(int64_t version, int parts, int by)
|
|
1915
2000
|
{
|
|
1916
2001
|
K_ASSERT(version >= 0);
|
|
@@ -1963,7 +2048,7 @@ const char *GetEnv(const char *name)
|
|
|
1963
2048
|
static HashMap<const char *, const char *> values;
|
|
1964
2049
|
|
|
1965
2050
|
bool inserted;
|
|
1966
|
-
auto bucket = values.
|
|
2051
|
+
auto bucket = values.InsertOrGetDefault(name, &inserted);
|
|
1967
2052
|
|
|
1968
2053
|
if (inserted) {
|
|
1969
2054
|
const char *str = (const char *)EM_ASM_INT({
|
|
@@ -2046,7 +2131,7 @@ void LogFmt(LogLevel level, const char *ctx, const char *fmt, Span<const FmtArg>
|
|
|
2046
2131
|
char ctx_buf[512];
|
|
2047
2132
|
if (log_times) {
|
|
2048
2133
|
double time = (double)(GetMonotonicTime() - start_time) / 1000;
|
|
2049
|
-
Fmt(ctx_buf, "[%1] %2", FmtDouble(time, 3
|
|
2134
|
+
Fmt(ctx_buf, "[%1] %2", FmtDouble(time, 3, 8), ctx ? ctx : "");
|
|
2050
2135
|
|
|
2051
2136
|
ctx = ctx_buf;
|
|
2052
2137
|
}
|
|
@@ -2383,13 +2468,13 @@ void DefaultProgressHandler(Span<const ProgressInfo> bars)
|
|
|
2383
2468
|
int progress = (int)(100 * delta / range);
|
|
2384
2469
|
int size = progress / 4;
|
|
2385
2470
|
|
|
2386
|
-
buf.len += Fmt(buf.TakeAvailable(), true, "%!..+[%1%2]%!0 %3\n",
|
|
2471
|
+
buf.len += Fmt(buf.TakeAvailable(), true, "%!..+[%1%2]%!0 %3\n", FmtRepeat("=", size), FmtRepeat(" ", 25 - size), bar.text).len;
|
|
2387
2472
|
} else {
|
|
2388
2473
|
int progress = (int)(frame % 44);
|
|
2389
2474
|
int before = (progress > 22) ? (44 - progress) : progress;
|
|
2390
2475
|
int after = std::max(22 - before, 0);
|
|
2391
2476
|
|
|
2392
|
-
buf.len += Fmt(buf.TakeAvailable(), true, "%!..+[%1===%2]%!0 %3\n",
|
|
2477
|
+
buf.len += Fmt(buf.TakeAvailable(), true, "%!..+[%1===%2]%!0 %3\n", FmtRepeat(" ", before), FmtRepeat(" ", after), bar.text).len;
|
|
2393
2478
|
}
|
|
2394
2479
|
}
|
|
2395
2480
|
|
|
@@ -2668,7 +2753,7 @@ bool ResizeFile(int fd, const char *filename, int64_t len)
|
|
|
2668
2753
|
return true;
|
|
2669
2754
|
}
|
|
2670
2755
|
|
|
2671
|
-
bool
|
|
2756
|
+
bool SetFileTimes(int fd, const char *filename, int64_t mtime, int64_t btime)
|
|
2672
2757
|
{
|
|
2673
2758
|
HANDLE h = (HANDLE)_get_osfhandle(fd);
|
|
2674
2759
|
|
|
@@ -3117,25 +3202,61 @@ bool ResizeFile(int fd, const char *filename, int64_t len)
|
|
|
3117
3202
|
return true;
|
|
3118
3203
|
}
|
|
3119
3204
|
|
|
3120
|
-
bool
|
|
3205
|
+
bool SetFileMode(int fd, const char *filename, uint32_t mode)
|
|
3206
|
+
{
|
|
3207
|
+
if (fd >= 0) {
|
|
3208
|
+
if (fchmod(fd, (mode_t)mode) < 0) {
|
|
3209
|
+
LogError("Failed to set permissions of '%1': %2", filename, strerror(errno));
|
|
3210
|
+
return false;
|
|
3211
|
+
}
|
|
3212
|
+
} else {
|
|
3213
|
+
if (fchmodat(AT_FDCWD, filename, (mode_t)mode, AT_SYMLINK_NOFOLLOW) < 0) {
|
|
3214
|
+
LogError("Failed to set permissions of '%1': %2", filename, strerror(errno));
|
|
3215
|
+
return false;
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
return true;
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
bool SetFileOwner(int fd, const char *filename, uint32_t uid, uint32_t gid)
|
|
3223
|
+
{
|
|
3224
|
+
if (fd >= 0) {
|
|
3225
|
+
if (fchown(fd, (uid_t)uid, (gid_t)gid) < 0) {
|
|
3226
|
+
LogError("Failed to change owner of '%1': %2", filename, strerror(errno));
|
|
3227
|
+
return false;
|
|
3228
|
+
}
|
|
3229
|
+
} else {
|
|
3230
|
+
if (lchown(filename, (uid_t)uid, (gid_t)gid) < 0) {
|
|
3231
|
+
LogError("Failed to change owner of '%1': %2", filename, strerror(errno));
|
|
3232
|
+
return false;
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
|
|
3236
|
+
return true;
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
bool SetFileTimes(int fd, const char *filename, int64_t mtime, int64_t)
|
|
3121
3240
|
{
|
|
3122
3241
|
struct timespec times[2] = {};
|
|
3123
|
-
bool valid = true;
|
|
3124
3242
|
|
|
3125
3243
|
times[0].tv_nsec = UTIME_OMIT;
|
|
3126
3244
|
times[1].tv_sec = mtime / 1000;
|
|
3127
3245
|
times[1].tv_nsec = (mtime % 1000) * 1000000;
|
|
3128
3246
|
|
|
3129
|
-
if (
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3247
|
+
if (fd >= 0) {
|
|
3248
|
+
if (futimens(fd, times) < 0) {
|
|
3249
|
+
LogError("Failed to set modification time of '%1': %2", filename, strerror(errno));
|
|
3250
|
+
return false;
|
|
3251
|
+
}
|
|
3252
|
+
} else {
|
|
3253
|
+
if (utimensat(AT_FDCWD, filename, times, AT_SYMLINK_NOFOLLOW) < 0) {
|
|
3254
|
+
LogError("Failed to set modification time of '%1': %2", filename, strerror(errno));
|
|
3255
|
+
return false;
|
|
3256
|
+
}
|
|
3136
3257
|
}
|
|
3137
3258
|
|
|
3138
|
-
return
|
|
3259
|
+
return true;
|
|
3139
3260
|
}
|
|
3140
3261
|
|
|
3141
3262
|
#if !defined(__wasm__)
|
|
@@ -3748,7 +3869,7 @@ const char *GetApplicationExecutable()
|
|
|
3748
3869
|
|
|
3749
3870
|
size_t argc;
|
|
3750
3871
|
{
|
|
3751
|
-
int ret = sysctl(name, K_LEN(name), nullptr, &argc,
|
|
3872
|
+
int ret = sysctl(name, K_LEN(name), nullptr, &argc, nullptr, 0);
|
|
3752
3873
|
K_ASSERT(ret >= 0);
|
|
3753
3874
|
K_ASSERT(argc >= 1);
|
|
3754
3875
|
}
|
|
@@ -3783,7 +3904,7 @@ const char *GetApplicationExecutable()
|
|
|
3783
3904
|
int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
|
|
3784
3905
|
size_t len = sizeof(executable_path);
|
|
3785
3906
|
|
|
3786
|
-
int ret = sysctl(name, K_LEN(name), executable_path, &len,
|
|
3907
|
+
int ret = sysctl(name, K_LEN(name), executable_path, &len, nullptr, 0);
|
|
3787
3908
|
K_ASSERT(ret >= 0);
|
|
3788
3909
|
K_ASSERT(len < K_SIZE(executable_path));
|
|
3789
3910
|
}
|
|
@@ -3852,13 +3973,6 @@ Span<const char> GetPathExtension(Span<const char> filename, CompressionType *ou
|
|
|
3852
3973
|
return extension;
|
|
3853
3974
|
}
|
|
3854
3975
|
|
|
3855
|
-
CompressionType GetPathCompression(Span<const char> filename)
|
|
3856
|
-
{
|
|
3857
|
-
CompressionType compression_type;
|
|
3858
|
-
GetPathExtension(filename, &compression_type);
|
|
3859
|
-
return compression_type;
|
|
3860
|
-
}
|
|
3861
|
-
|
|
3862
3976
|
Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, unsigned int flags, Allocator *alloc)
|
|
3863
3977
|
{
|
|
3864
3978
|
K_ASSERT(alloc);
|
|
@@ -3866,6 +3980,21 @@ Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory,
|
|
|
3866
3980
|
if (!path.len && !root_directory.len)
|
|
3867
3981
|
return Fmt(alloc, "");
|
|
3868
3982
|
|
|
3983
|
+
#if !defined(_WIN32)
|
|
3984
|
+
if (!(flags & (int)NormalizeFlag::NoExpansion)) {
|
|
3985
|
+
Span<const char> prefix = SplitStrAny(path, K_PATH_SEPARATORS);
|
|
3986
|
+
|
|
3987
|
+
if (prefix == "~") {
|
|
3988
|
+
const char *home = GetEnv("HOME");
|
|
3989
|
+
|
|
3990
|
+
if (home) {
|
|
3991
|
+
root_directory = home;
|
|
3992
|
+
path = TrimStrLeft(path.Take(1, path.len - 1), K_PATH_SEPARATORS);
|
|
3993
|
+
}
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3996
|
+
#endif
|
|
3997
|
+
|
|
3869
3998
|
HeapArray<char> buf(alloc);
|
|
3870
3999
|
Size parts_count = 0;
|
|
3871
4000
|
|
|
@@ -3906,15 +4035,17 @@ Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory,
|
|
|
3906
4035
|
|
|
3907
4036
|
if (!buf.len) {
|
|
3908
4037
|
buf.Append('.');
|
|
4038
|
+
|
|
4039
|
+
if (flags & (int)NormalizeFlag::EndWithSeparator) {
|
|
4040
|
+
buf.Append(separator);
|
|
4041
|
+
}
|
|
3909
4042
|
} else if (buf.len == 1 && IsPathSeparator(buf[0])) {
|
|
3910
|
-
// Root '/', keep as-is
|
|
3911
|
-
|
|
4043
|
+
// Root '/', keep as-is or almost
|
|
4044
|
+
buf[0] = separator;
|
|
4045
|
+
} else if (!(flags & (int)NormalizeFlag::EndWithSeparator)) {
|
|
3912
4046
|
// Strip last separator
|
|
3913
4047
|
buf.len--;
|
|
3914
4048
|
}
|
|
3915
|
-
if (flags & (int)NormalizeFlag::EndWithSeparator) {
|
|
3916
|
-
buf.Append(separator);
|
|
3917
|
-
}
|
|
3918
4049
|
|
|
3919
4050
|
#if defined(_WIN32)
|
|
3920
4051
|
if (buf.len >= 2 && IsAsciiAlpha(buf[0]) && buf[1] == ':') {
|
|
@@ -3961,6 +4092,20 @@ bool PathContainsDotDot(const char *path)
|
|
|
3961
4092
|
return false;
|
|
3962
4093
|
}
|
|
3963
4094
|
|
|
4095
|
+
bool PathContainsDotDot(Span<const char> path)
|
|
4096
|
+
{
|
|
4097
|
+
const char *ptr = path.ptr;
|
|
4098
|
+
const char *end = path.end();
|
|
4099
|
+
|
|
4100
|
+
while ((ptr = (const char *)MemMem(ptr, end - ptr, "..", 2))) {
|
|
4101
|
+
if ((ptr == path.ptr || IsPathSeparator(ptr[-1])) && (ptr + 2 == end || IsPathSeparator(ptr[2])))
|
|
4102
|
+
return true;
|
|
4103
|
+
ptr += 2;
|
|
4104
|
+
}
|
|
4105
|
+
|
|
4106
|
+
return false;
|
|
4107
|
+
}
|
|
4108
|
+
|
|
3964
4109
|
static bool CheckForDumbTerm()
|
|
3965
4110
|
{
|
|
3966
4111
|
static bool dumb = ([]() {
|
|
@@ -4777,6 +4922,7 @@ bool EnsureDirectoryExists(const char *filename)
|
|
|
4777
4922
|
|
|
4778
4923
|
#if defined(_WIN32)
|
|
4779
4924
|
|
|
4925
|
+
static const DWORD main_thread = GetCurrentThreadId();
|
|
4780
4926
|
static HANDLE console_ctrl_event = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
|
4781
4927
|
static bool ignore_ctrl_event = false;
|
|
4782
4928
|
|
|
@@ -4811,7 +4957,7 @@ bool CreateOverlappedPipe(bool overlap0, bool overlap1, PipeMode mode, HANDLE ou
|
|
|
4811
4957
|
|
|
4812
4958
|
char pipe_name[128];
|
|
4813
4959
|
do {
|
|
4814
|
-
Fmt(pipe_name, "\\\\.\\
|
|
4960
|
+
Fmt(pipe_name, "\\\\.\\pipe\\kcc.%1.%2",
|
|
4815
4961
|
GetCurrentProcessId(), InterlockedIncrement(&pipe_idx));
|
|
4816
4962
|
|
|
4817
4963
|
DWORD open_mode = PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | (overlap0 ? FILE_FLAG_OVERLAPPED : 0);
|
|
@@ -5138,12 +5284,11 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
|
5138
5284
|
|
|
5139
5285
|
#else
|
|
5140
5286
|
|
|
5141
|
-
#if defined(__OpenBSD__) || defined(__FreeBSD__)
|
|
5142
5287
|
static const pthread_t main_thread = pthread_self();
|
|
5143
|
-
|
|
5288
|
+
|
|
5144
5289
|
static std::atomic_bool flag_signal { false };
|
|
5145
5290
|
static std::atomic_int explicit_signal { 0 };
|
|
5146
|
-
static
|
|
5291
|
+
static std::atomic_int interrupt_pfd[2] { -1, -1 };
|
|
5147
5292
|
|
|
5148
5293
|
void SetSignalHandler(int signal, void (*func)(int), struct sigaction *prev)
|
|
5149
5294
|
{
|
|
@@ -5158,19 +5303,17 @@ void SetSignalHandler(int signal, void (*func)(int), struct sigaction *prev)
|
|
|
5158
5303
|
|
|
5159
5304
|
static void DefaultSignalHandler(int signal)
|
|
5160
5305
|
{
|
|
5161
|
-
|
|
5162
|
-
if (!pthread_main_np()) {
|
|
5306
|
+
if (pthread_self() != main_thread) {
|
|
5163
5307
|
pthread_kill(main_thread, signal);
|
|
5164
5308
|
return;
|
|
5165
5309
|
}
|
|
5166
|
-
#endif
|
|
5167
5310
|
|
|
5168
5311
|
pid_t pid = getpid();
|
|
5169
5312
|
K_ASSERT(pid > 1);
|
|
5170
5313
|
|
|
5171
|
-
if (interrupt_pfd[1] >= 0) {
|
|
5314
|
+
if (int fd = interrupt_pfd[1].load(); fd >= 0) {
|
|
5172
5315
|
char dummy = 0;
|
|
5173
|
-
K_IGNORE write(
|
|
5316
|
+
K_IGNORE write(fd, &dummy, 1);
|
|
5174
5317
|
}
|
|
5175
5318
|
|
|
5176
5319
|
if (flag_signal) {
|
|
@@ -5181,26 +5324,30 @@ static void DefaultSignalHandler(int signal)
|
|
|
5181
5324
|
}
|
|
5182
5325
|
}
|
|
5183
5326
|
|
|
5184
|
-
bool CreatePipe(int
|
|
5327
|
+
bool CreatePipe(bool block, int out_pfd[2])
|
|
5185
5328
|
{
|
|
5186
5329
|
#if defined(__APPLE__)
|
|
5187
|
-
if (pipe(
|
|
5330
|
+
if (pipe(out_pfd) < 0) {
|
|
5188
5331
|
LogError("Failed to create pipe: %1", strerror(errno));
|
|
5189
5332
|
return false;
|
|
5190
5333
|
}
|
|
5191
5334
|
|
|
5192
|
-
if (fcntl(
|
|
5335
|
+
if (fcntl(out_pfd[0], F_SETFD, FD_CLOEXEC) < 0 || fcntl(out_pfd[1], F_SETFD, FD_CLOEXEC) < 0) {
|
|
5193
5336
|
LogError("Failed to set FD_CLOEXEC on pipe: %1", strerror(errno));
|
|
5194
5337
|
return false;
|
|
5195
5338
|
}
|
|
5196
|
-
if (
|
|
5197
|
-
|
|
5198
|
-
|
|
5339
|
+
if (!block) {
|
|
5340
|
+
if (fcntl(out_pfd[0], F_SETFL, O_NONBLOCK) < 0 || fcntl(out_pfd[1], F_SETFL, O_NONBLOCK) < 0) {
|
|
5341
|
+
LogError("Failed to set O_NONBLOCK on pipe: %1", strerror(errno));
|
|
5342
|
+
return false;
|
|
5343
|
+
}
|
|
5199
5344
|
}
|
|
5200
5345
|
|
|
5201
5346
|
return true;
|
|
5202
5347
|
#else
|
|
5203
|
-
|
|
5348
|
+
int flags = O_CLOEXEC | (block ? 0 : O_NONBLOCK);
|
|
5349
|
+
|
|
5350
|
+
if (pipe2(out_pfd, flags) < 0) {
|
|
5204
5351
|
LogError("Failed to create pipe: %1", strerror(errno));
|
|
5205
5352
|
return false;
|
|
5206
5353
|
}
|
|
@@ -5218,6 +5365,28 @@ void CloseDescriptorSafe(int *fd_ptr)
|
|
|
5218
5365
|
*fd_ptr = -1;
|
|
5219
5366
|
}
|
|
5220
5367
|
|
|
5368
|
+
static void InitInterruptPipe()
|
|
5369
|
+
{
|
|
5370
|
+
static bool success = ([]() {
|
|
5371
|
+
static int pfd[2];
|
|
5372
|
+
|
|
5373
|
+
if (!CreatePipe(false, pfd))
|
|
5374
|
+
return false;
|
|
5375
|
+
|
|
5376
|
+
atexit([]() {
|
|
5377
|
+
CloseDescriptor(pfd[0]);
|
|
5378
|
+
CloseDescriptor(pfd[1]);
|
|
5379
|
+
});
|
|
5380
|
+
|
|
5381
|
+
interrupt_pfd[0] = pfd[0];
|
|
5382
|
+
interrupt_pfd[1] = pfd[1];
|
|
5383
|
+
|
|
5384
|
+
return true;
|
|
5385
|
+
})();
|
|
5386
|
+
|
|
5387
|
+
K_CRITICAL(success, "Failed to create interrupt pipe");
|
|
5388
|
+
}
|
|
5389
|
+
|
|
5221
5390
|
bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
5222
5391
|
FunctionRef<Span<const uint8_t>()> in_func,
|
|
5223
5392
|
FunctionRef<void(Span<uint8_t> buf)> out_func, int *out_code)
|
|
@@ -5231,12 +5400,8 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
|
5231
5400
|
CloseDescriptorSafe(&in_pfd[1]);
|
|
5232
5401
|
};
|
|
5233
5402
|
if (in_func.IsValid()) {
|
|
5234
|
-
if (!CreatePipe(in_pfd))
|
|
5235
|
-
return false;
|
|
5236
|
-
if (fcntl(in_pfd[1], F_SETFL, O_NONBLOCK) < 0) {
|
|
5237
|
-
LogError("Failed to set O_NONBLOCK on pipe: %1", strerror(errno));
|
|
5403
|
+
if (!CreatePipe(false, in_pfd))
|
|
5238
5404
|
return false;
|
|
5239
|
-
}
|
|
5240
5405
|
}
|
|
5241
5406
|
|
|
5242
5407
|
// Create write pipes
|
|
@@ -5246,33 +5411,11 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
|
5246
5411
|
CloseDescriptorSafe(&out_pfd[1]);
|
|
5247
5412
|
};
|
|
5248
5413
|
if (out_func.IsValid()) {
|
|
5249
|
-
if (!CreatePipe(out_pfd))
|
|
5250
|
-
return false;
|
|
5251
|
-
if (fcntl(out_pfd[0], F_SETFL, O_NONBLOCK) < 0) {
|
|
5252
|
-
LogError("Failed to set O_NONBLOCK on pipe: %1", strerror(errno));
|
|
5414
|
+
if (!CreatePipe(false, out_pfd))
|
|
5253
5415
|
return false;
|
|
5254
|
-
}
|
|
5255
5416
|
}
|
|
5256
5417
|
|
|
5257
|
-
|
|
5258
|
-
{
|
|
5259
|
-
static bool success = ([]() {
|
|
5260
|
-
if (!CreatePipe(interrupt_pfd))
|
|
5261
|
-
return false;
|
|
5262
|
-
|
|
5263
|
-
atexit([]() {
|
|
5264
|
-
CloseDescriptorSafe(&interrupt_pfd[0]);
|
|
5265
|
-
CloseDescriptorSafe(&interrupt_pfd[1]);
|
|
5266
|
-
});
|
|
5267
|
-
|
|
5268
|
-
return true;
|
|
5269
|
-
})();
|
|
5270
|
-
|
|
5271
|
-
if (!success) {
|
|
5272
|
-
LogError("Failed to create termination pipe");
|
|
5273
|
-
return false;
|
|
5274
|
-
}
|
|
5275
|
-
}
|
|
5418
|
+
InitInterruptPipe();
|
|
5276
5419
|
|
|
5277
5420
|
// Prepare new environment (if needed)
|
|
5278
5421
|
HeapArray<char *> new_env;
|
|
@@ -5345,9 +5488,9 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
|
5345
5488
|
out_idx = pfds.len;
|
|
5346
5489
|
pfds.Append({ out_pfd[0], POLLIN, 0 });
|
|
5347
5490
|
}
|
|
5348
|
-
if (interrupt_pfd[0] >= 0) {
|
|
5491
|
+
if (int fd = interrupt_pfd[0].load(); fd >= 0) {
|
|
5349
5492
|
term_idx = pfds.len;
|
|
5350
|
-
pfds.Append({
|
|
5493
|
+
pfds.Append({ fd, POLLIN, 0 });
|
|
5351
5494
|
}
|
|
5352
5495
|
|
|
5353
5496
|
if (K_RESTART_EINTR(poll(pfds.data, (nfds_t)pfds.len, -1), < 0) < 0) {
|
|
@@ -5575,9 +5718,9 @@ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t
|
|
|
5575
5718
|
|
|
5576
5719
|
LocalArray<HANDLE, 64> events;
|
|
5577
5720
|
DWORD wake = 0;
|
|
5721
|
+
DWORD wait_ret = 0;
|
|
5578
5722
|
|
|
5579
5723
|
events.Append(console_ctrl_event);
|
|
5580
|
-
events.Append(wait_msg_event);
|
|
5581
5724
|
|
|
5582
5725
|
// There is no way to get a waitable HANDLE for the Win32 GUI message pump.
|
|
5583
5726
|
// Instead, waitable sources (such as the system tray code) return NULL to indicate that
|
|
@@ -5592,6 +5735,11 @@ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t
|
|
|
5592
5735
|
timeout = (int64_t)std::min((uint64_t)timeout, (uint64_t)src.timeout);
|
|
5593
5736
|
}
|
|
5594
5737
|
|
|
5738
|
+
if (main_thread == GetCurrentThreadId()) {
|
|
5739
|
+
wait_ret = WAIT_OBJECT_0 + (DWORD)events.len;
|
|
5740
|
+
events.Append(wait_msg_event);
|
|
5741
|
+
}
|
|
5742
|
+
|
|
5595
5743
|
DWORD ret;
|
|
5596
5744
|
if (timeout >= 0) {
|
|
5597
5745
|
do {
|
|
@@ -5604,34 +5752,31 @@ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t
|
|
|
5604
5752
|
ret = MsgWaitForMultipleObjects((DWORD)events.len, events.data, FALSE, INFINITE, wake);
|
|
5605
5753
|
}
|
|
5606
5754
|
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
}
|
|
5621
|
-
*out_ready = flags;
|
|
5622
|
-
}
|
|
5623
|
-
return WaitResult::Ready;
|
|
5755
|
+
if (ret == WAIT_TIMEOUT) {
|
|
5756
|
+
return WaitResult::Timeout;
|
|
5757
|
+
} else if (ret == WAIT_OBJECT_0) {
|
|
5758
|
+
return WaitResult::Interrupt;
|
|
5759
|
+
} else if (ret == wait_ret) {
|
|
5760
|
+
ResetEvent(wait_msg_event);
|
|
5761
|
+
return WaitResult::Message;
|
|
5762
|
+
} else if (ret == WAIT_OBJECT_0 + events.len) {
|
|
5763
|
+
// Mark all sources with an interest in the message pump as ready
|
|
5764
|
+
if (out_ready) {
|
|
5765
|
+
uint64_t flags = 0;
|
|
5766
|
+
for (Size i = 0; i < sources.len; i++) {
|
|
5767
|
+
flags |= !sources[i].handle ? (1ull << i) : 0;
|
|
5624
5768
|
}
|
|
5769
|
+
*out_ready = flags;
|
|
5770
|
+
}
|
|
5771
|
+
return WaitResult::Ready;
|
|
5772
|
+
} else {
|
|
5773
|
+
Size idx = (Size)ret - WAIT_OBJECT_0 - 1;
|
|
5774
|
+
K_ASSERT(idx >= 0 && idx < sources.len);
|
|
5625
5775
|
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
*out_ready |= 1ull << idx;
|
|
5631
|
-
}
|
|
5632
|
-
return WaitResult::Ready;
|
|
5633
|
-
} break;
|
|
5634
|
-
case WAIT_TIMEOUT: return WaitResult::Timeout;
|
|
5776
|
+
if (out_ready) {
|
|
5777
|
+
*out_ready |= 1ull << idx;
|
|
5778
|
+
}
|
|
5779
|
+
return WaitResult::Ready;
|
|
5635
5780
|
}
|
|
5636
5781
|
}
|
|
5637
5782
|
|
|
@@ -5641,11 +5786,16 @@ WaitResult WaitEvents(int64_t timeout)
|
|
|
5641
5786
|
return WaitEvents(sources, timeout);
|
|
5642
5787
|
}
|
|
5643
5788
|
|
|
5644
|
-
void
|
|
5789
|
+
void PostWaitMessage()
|
|
5645
5790
|
{
|
|
5646
5791
|
SetEvent(wait_msg_event);
|
|
5647
5792
|
}
|
|
5648
5793
|
|
|
5794
|
+
void PostTerminate()
|
|
5795
|
+
{
|
|
5796
|
+
SetEvent(console_ctrl_event);
|
|
5797
|
+
}
|
|
5798
|
+
|
|
5649
5799
|
#else
|
|
5650
5800
|
|
|
5651
5801
|
void WaitDelay(int64_t delay)
|
|
@@ -5669,18 +5819,24 @@ void WaitDelay(int64_t delay)
|
|
|
5669
5819
|
WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready)
|
|
5670
5820
|
{
|
|
5671
5821
|
LocalArray<struct pollfd, 64> pfds;
|
|
5672
|
-
K_ASSERT(sources.len <= K_LEN(pfds.data));
|
|
5673
|
-
|
|
5674
|
-
static std::atomic_bool message { false };
|
|
5822
|
+
K_ASSERT(sources.len <= K_LEN(pfds.data) - 1);
|
|
5675
5823
|
|
|
5824
|
+
// Don't exit after SIGINT/SIGTERM, just signal us
|
|
5676
5825
|
flag_signal = true;
|
|
5826
|
+
|
|
5827
|
+
static std::atomic_bool message { false };
|
|
5677
5828
|
SetSignalHandler(SIGUSR1, [](int) { message = true; });
|
|
5678
5829
|
|
|
5679
5830
|
for (const WaitSource &src: sources) {
|
|
5680
|
-
|
|
5831
|
+
short events = src.events ? (short)src.events : POLLIN;
|
|
5832
|
+
pfds.Append({ src.fd, events, 0 });
|
|
5833
|
+
|
|
5681
5834
|
timeout = (int64_t)std::min((uint64_t)timeout, (uint64_t)src.timeout);
|
|
5682
5835
|
}
|
|
5683
5836
|
|
|
5837
|
+
InitInterruptPipe();
|
|
5838
|
+
pfds.Append({ interrupt_pfd[0], POLLIN, 0 });
|
|
5839
|
+
|
|
5684
5840
|
int64_t start = (timeout >= 0) ? GetMonotonicTime() : 0;
|
|
5685
5841
|
int64_t until = start + timeout;
|
|
5686
5842
|
int timeout32 = (int)std::min(until - start, (int64_t)INT_MAX);
|
|
@@ -5690,7 +5846,7 @@ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t
|
|
|
5690
5846
|
return WaitResult::Exit;
|
|
5691
5847
|
} else if (explicit_signal) {
|
|
5692
5848
|
return WaitResult::Interrupt;
|
|
5693
|
-
} else if (message) {
|
|
5849
|
+
} else if (message && pthread_self() == main_thread) {
|
|
5694
5850
|
message = false;
|
|
5695
5851
|
return WaitResult::Message;
|
|
5696
5852
|
}
|
|
@@ -5702,16 +5858,19 @@ WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t
|
|
|
5702
5858
|
continue;
|
|
5703
5859
|
|
|
5704
5860
|
LogError("Failed to poll for events: %1", strerror(errno));
|
|
5705
|
-
|
|
5861
|
+
abort();
|
|
5706
5862
|
} else if (ready > 0) {
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5863
|
+
uint64_t flags = 0;
|
|
5864
|
+
for (Size i = 0; i < pfds.len - 1; i++) {
|
|
5865
|
+
flags |= pfds[i].revents ? (1ull << i) : 0;
|
|
5866
|
+
}
|
|
5867
|
+
|
|
5868
|
+
if (flags) {
|
|
5869
|
+
if (out_ready) {
|
|
5870
|
+
*out_ready = flags;
|
|
5711
5871
|
}
|
|
5712
|
-
|
|
5872
|
+
return WaitResult::Ready;
|
|
5713
5873
|
}
|
|
5714
|
-
return WaitResult::Ready;
|
|
5715
5874
|
}
|
|
5716
5875
|
|
|
5717
5876
|
if (timeout >= 0) {
|
|
@@ -5731,12 +5890,20 @@ WaitResult WaitEvents(int64_t timeout)
|
|
|
5731
5890
|
return WaitEvents(sources, timeout);
|
|
5732
5891
|
}
|
|
5733
5892
|
|
|
5734
|
-
void
|
|
5893
|
+
void PostWaitMessage()
|
|
5735
5894
|
{
|
|
5736
5895
|
pid_t pid = getpid();
|
|
5737
5896
|
kill(pid, SIGUSR1);
|
|
5738
5897
|
}
|
|
5739
5898
|
|
|
5899
|
+
void PostTerminate()
|
|
5900
|
+
{
|
|
5901
|
+
InitInterruptPipe();
|
|
5902
|
+
|
|
5903
|
+
char dummy = 0;
|
|
5904
|
+
K_IGNORE write(interrupt_pfd[1], &dummy, 1);
|
|
5905
|
+
}
|
|
5906
|
+
|
|
5740
5907
|
#endif
|
|
5741
5908
|
|
|
5742
5909
|
#endif
|
|
@@ -5837,30 +6004,30 @@ error:
|
|
|
5837
6004
|
|
|
5838
6005
|
bool NotifySystemd()
|
|
5839
6006
|
{
|
|
5840
|
-
const char *
|
|
5841
|
-
if (!
|
|
6007
|
+
const char *addr = GetEnv("NOTIFY_SOCKET");
|
|
6008
|
+
if (!addr)
|
|
5842
6009
|
return true;
|
|
5843
6010
|
|
|
5844
|
-
struct sockaddr_un
|
|
5845
|
-
if (
|
|
5846
|
-
|
|
6011
|
+
struct sockaddr_un sa;
|
|
6012
|
+
if (addr[0] == '@') {
|
|
6013
|
+
addr++;
|
|
5847
6014
|
|
|
5848
|
-
if (strlen(
|
|
6015
|
+
if (strlen(addr) >= sizeof(sa.sun_path) - 1) {
|
|
5849
6016
|
LogError("Abstract socket address in NOTIFY_SOCKET is too long");
|
|
5850
6017
|
return false;
|
|
5851
6018
|
}
|
|
5852
6019
|
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
CopyString(
|
|
5856
|
-
} else if (
|
|
5857
|
-
if (strlen(
|
|
6020
|
+
sa.sun_family = AF_UNIX;
|
|
6021
|
+
sa.sun_path[0] = 0;
|
|
6022
|
+
CopyString(addr, MakeSpan(sa.sun_path + 1, K_SIZE(sa.sun_path) - 1));
|
|
6023
|
+
} else if (addr[0] == '/') {
|
|
6024
|
+
if (strlen(addr) >= sizeof(sa.sun_path)) {
|
|
5858
6025
|
LogError("Socket pathname in NOTIFY_SOCKET is too long");
|
|
5859
6026
|
return false;
|
|
5860
6027
|
}
|
|
5861
6028
|
|
|
5862
|
-
|
|
5863
|
-
CopyString(
|
|
6029
|
+
sa.sun_family = AF_UNIX;
|
|
6030
|
+
CopyString(addr, sa.sun_path);
|
|
5864
6031
|
} else {
|
|
5865
6032
|
LogError("Invalid socket address in NOTIFY_SOCKET");
|
|
5866
6033
|
return false;
|
|
@@ -5877,8 +6044,8 @@ bool NotifySystemd()
|
|
|
5877
6044
|
struct msghdr msg = {};
|
|
5878
6045
|
iov.iov_base = (void *)"READY=1";
|
|
5879
6046
|
iov.iov_len = strlen("READY=1");
|
|
5880
|
-
msg.msg_name = &
|
|
5881
|
-
msg.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(
|
|
6047
|
+
msg.msg_name = &sa;
|
|
6048
|
+
msg.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(addr);
|
|
5882
6049
|
msg.msg_iov = &iov;
|
|
5883
6050
|
msg.msg_iovlen = 1;
|
|
5884
6051
|
|
|
@@ -5927,25 +6094,13 @@ void InitApp()
|
|
|
5927
6094
|
#endif
|
|
5928
6095
|
|
|
5929
6096
|
#if !defined(_WIN32) && !defined(__wasi__)
|
|
5930
|
-
// Best effort
|
|
5931
|
-
setpgid(0, 0);
|
|
5932
|
-
|
|
5933
6097
|
// Setup default signal handlers
|
|
5934
6098
|
SetSignalHandler(SIGINT, DefaultSignalHandler);
|
|
5935
6099
|
SetSignalHandler(SIGTERM, DefaultSignalHandler);
|
|
5936
6100
|
SetSignalHandler(SIGHUP, DefaultSignalHandler);
|
|
5937
6101
|
SetSignalHandler(SIGPIPE, [](int) {});
|
|
5938
6102
|
|
|
5939
|
-
|
|
5940
|
-
atexit([]() {
|
|
5941
|
-
if (interrupt_pfd[1] >= 0) {
|
|
5942
|
-
pid_t pid = getpid();
|
|
5943
|
-
K_ASSERT(pid > 1);
|
|
5944
|
-
|
|
5945
|
-
SetSignalHandler(SIGTERM, [](int) {});
|
|
5946
|
-
kill(-pid, SIGTERM);
|
|
5947
|
-
}
|
|
5948
|
-
});
|
|
6103
|
+
InitInterruptPipe();
|
|
5949
6104
|
|
|
5950
6105
|
// Make sure timezone information is in place, which is useful if some kind of sandbox runs later and
|
|
5951
6106
|
// the timezone information is not available (seccomp, namespace, landlock, whatever).
|
|
@@ -6981,39 +7136,65 @@ int CreateSocket(SocketType type, int flags)
|
|
|
6981
7136
|
|
|
6982
7137
|
#endif
|
|
6983
7138
|
|
|
6984
|
-
bool BindIPSocket(int sock, SocketType type, int port)
|
|
7139
|
+
bool BindIPSocket(int sock, SocketType type, const char *addr, int port)
|
|
6985
7140
|
{
|
|
6986
7141
|
K_ASSERT(type == SocketType::Dual || type == SocketType::IPv4 || type == SocketType::IPv6);
|
|
6987
7142
|
|
|
6988
7143
|
if (type == SocketType::IPv4) {
|
|
6989
|
-
struct sockaddr_in
|
|
7144
|
+
struct sockaddr_in sa = {};
|
|
7145
|
+
|
|
7146
|
+
sa.sin_family = AF_INET;
|
|
7147
|
+
sa.sin_port = htons((uint16_t)port);
|
|
6990
7148
|
|
|
6991
|
-
addr
|
|
6992
|
-
|
|
6993
|
-
|
|
7149
|
+
if (addr) {
|
|
7150
|
+
if (inet_pton(AF_INET, addr, &sa.sin_addr) <= 0) {
|
|
7151
|
+
LogError("Invalid IPv4 address '%1'", addr);
|
|
7152
|
+
return false;
|
|
7153
|
+
}
|
|
7154
|
+
} else {
|
|
7155
|
+
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
7156
|
+
}
|
|
6994
7157
|
|
|
6995
|
-
if (bind(sock, (struct sockaddr *)&
|
|
7158
|
+
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
|
6996
7159
|
#if defined(_WIN32)
|
|
6997
|
-
LogError("Failed to bind to
|
|
7160
|
+
LogError("Failed to bind to '%1:%2': %3", addr ? addr : "*", port, GetWin32ErrorString());
|
|
6998
7161
|
return false;
|
|
6999
7162
|
#else
|
|
7000
|
-
LogError("Failed to bind to
|
|
7163
|
+
LogError("Failed to bind to '%1:%2': %3", addr ? addr : "*", port, strerror(errno));
|
|
7001
7164
|
return false;
|
|
7002
7165
|
#endif
|
|
7003
7166
|
}
|
|
7004
7167
|
} else {
|
|
7005
|
-
struct sockaddr_in6
|
|
7168
|
+
struct sockaddr_in6 sa = {};
|
|
7006
7169
|
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
addr.sin6_addr = IN6ADDR_ANY_INIT;
|
|
7170
|
+
sa.sin6_family = AF_INET6;
|
|
7171
|
+
sa.sin6_port = htons((uint16_t)port);
|
|
7010
7172
|
|
|
7011
|
-
if (
|
|
7173
|
+
if (addr) {
|
|
7174
|
+
if (!strchr(addr, ':')) {
|
|
7175
|
+
char buf[512];
|
|
7176
|
+
Fmt(buf, "::FFFF:%1", addr);
|
|
7177
|
+
|
|
7178
|
+
if (inet_pton(AF_INET6, buf, &sa.sin6_addr) <= 0) {
|
|
7179
|
+
LogError("Invalid IPv4 or IPv6 address '%1'", addr);
|
|
7180
|
+
return false;
|
|
7181
|
+
}
|
|
7182
|
+
} else {
|
|
7183
|
+
if (inet_pton(AF_INET6, addr, &sa.sin6_addr) <= 0) {
|
|
7184
|
+
LogError("Invalid IPv6 address '%1'", addr);
|
|
7185
|
+
return false;
|
|
7186
|
+
}
|
|
7187
|
+
}
|
|
7188
|
+
} else {
|
|
7189
|
+
sa.sin6_addr = IN6ADDR_ANY_INIT;
|
|
7190
|
+
}
|
|
7191
|
+
|
|
7192
|
+
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
|
7012
7193
|
#if defined(_WIN32)
|
|
7013
|
-
LogError("Failed to bind to
|
|
7194
|
+
LogError("Failed to bind to '%1:%2': %3", addr ? addr : "*", port, GetWin32ErrorString());
|
|
7014
7195
|
return false;
|
|
7015
7196
|
#else
|
|
7016
|
-
LogError("Failed to bind to
|
|
7197
|
+
LogError("Failed to bind to '%1:%2': %3", addr ? addr : "*", port, strerror(errno));
|
|
7017
7198
|
return false;
|
|
7018
7199
|
#endif
|
|
7019
7200
|
}
|
|
@@ -7024,16 +7205,32 @@ bool BindIPSocket(int sock, SocketType type, int port)
|
|
|
7024
7205
|
|
|
7025
7206
|
bool BindUnixSocket(int sock, const char *path)
|
|
7026
7207
|
{
|
|
7027
|
-
struct sockaddr_un
|
|
7208
|
+
struct sockaddr_un sa = {};
|
|
7209
|
+
|
|
7210
|
+
// Protect against abtract Unix sockets on Linux
|
|
7211
|
+
if (!path[0]) {
|
|
7212
|
+
LogError("Cannot open empty UNIX socket");
|
|
7213
|
+
return false;
|
|
7214
|
+
}
|
|
7028
7215
|
|
|
7029
|
-
|
|
7030
|
-
if (!CopyString(path,
|
|
7216
|
+
sa.sun_family = AF_UNIX;
|
|
7217
|
+
if (!CopyString(path, sa.sun_path)) {
|
|
7031
7218
|
LogError("Excessive UNIX socket path length");
|
|
7032
7219
|
return false;
|
|
7033
7220
|
}
|
|
7034
7221
|
|
|
7035
|
-
|
|
7036
|
-
|
|
7222
|
+
#if !defined(_WIN32)
|
|
7223
|
+
// Remove existing socket (if any)
|
|
7224
|
+
{
|
|
7225
|
+
struct stat sb;
|
|
7226
|
+
if (!stat(path, &sb) && S_ISSOCK(sb.st_mode)) {
|
|
7227
|
+
LogDebug("Removing existing socket '%1'", path);
|
|
7228
|
+
unlink(path);
|
|
7229
|
+
}
|
|
7230
|
+
}
|
|
7231
|
+
#endif
|
|
7232
|
+
|
|
7233
|
+
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
|
7037
7234
|
#if defined(_WIN32)
|
|
7038
7235
|
LogError("Failed to bind socket to '%1': %2", path, GetWin32ErrorString());
|
|
7039
7236
|
return false;
|
|
@@ -7042,68 +7239,82 @@ bool BindUnixSocket(int sock, const char *path)
|
|
|
7042
7239
|
return false;
|
|
7043
7240
|
#endif
|
|
7044
7241
|
}
|
|
7242
|
+
|
|
7243
|
+
#if !defined(_WIN32)
|
|
7045
7244
|
chmod(path, 0666);
|
|
7245
|
+
#endif
|
|
7046
7246
|
|
|
7047
7247
|
return true;
|
|
7048
7248
|
}
|
|
7049
7249
|
|
|
7050
|
-
|
|
7250
|
+
bool ConnectIPSocket(int sock, const char *addr, int port)
|
|
7051
7251
|
{
|
|
7052
|
-
|
|
7252
|
+
if (strchr(addr, ':')) {
|
|
7253
|
+
struct sockaddr_in6 sa = {};
|
|
7053
7254
|
|
|
7054
|
-
|
|
7055
|
-
|
|
7056
|
-
return -1;
|
|
7057
|
-
K_DEFER_N(err_guard) { CloseSocket(sock); };
|
|
7255
|
+
sa.sin6_family = AF_INET6;
|
|
7256
|
+
sa.sin6_port = htons((unsigned short)port);
|
|
7058
7257
|
|
|
7059
|
-
|
|
7060
|
-
|
|
7258
|
+
if (inet_pton(AF_INET6, addr, &sa.sin6_addr) <= 0) {
|
|
7259
|
+
LogError("Invalid IPv6 address '%1'", addr);
|
|
7260
|
+
return false;
|
|
7261
|
+
}
|
|
7061
7262
|
|
|
7062
|
-
|
|
7063
|
-
|
|
7064
|
-
|
|
7263
|
+
if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
|
7264
|
+
#if defined(_WIN32)
|
|
7265
|
+
LogError("Failed to connect to '%1' (%2): %3", addr, port, GetWin32ErrorString());
|
|
7266
|
+
return false;
|
|
7267
|
+
#else
|
|
7268
|
+
LogError("Failed to connect to '%1' (%2): %3", addr, port, strerror(errno));
|
|
7269
|
+
return false;
|
|
7270
|
+
#endif
|
|
7271
|
+
}
|
|
7272
|
+
} else {
|
|
7273
|
+
struct sockaddr_in sa = {};
|
|
7065
7274
|
|
|
7066
|
-
|
|
7067
|
-
|
|
7068
|
-
int sock = CreateSocket(SocketType::Unix, flags);
|
|
7069
|
-
if (sock < 0)
|
|
7070
|
-
return -1;
|
|
7071
|
-
K_DEFER_N(err_guard) { CloseSocket(sock); };
|
|
7275
|
+
sa.sin_family = AF_INET;
|
|
7276
|
+
sa.sin_port = htons((unsigned short)port);
|
|
7072
7277
|
|
|
7073
|
-
|
|
7074
|
-
|
|
7278
|
+
if (inet_pton(AF_INET, addr, &sa.sin_addr) <= 0) {
|
|
7279
|
+
LogError("Invalid IPv4 address '%1'", addr);
|
|
7280
|
+
return false;
|
|
7281
|
+
}
|
|
7075
7282
|
|
|
7076
|
-
|
|
7077
|
-
|
|
7283
|
+
if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
|
7284
|
+
#if defined(_WIN32)
|
|
7285
|
+
LogError("Failed to connect to '%1' (%2): %3", addr, port, GetWin32ErrorString());
|
|
7286
|
+
return false;
|
|
7287
|
+
#else
|
|
7288
|
+
LogError("Failed to connect to '%1' (%2): %3", addr, port, strerror(errno));
|
|
7289
|
+
return false;
|
|
7290
|
+
#endif
|
|
7291
|
+
}
|
|
7292
|
+
}
|
|
7293
|
+
|
|
7294
|
+
return true;
|
|
7078
7295
|
}
|
|
7079
7296
|
|
|
7080
|
-
int
|
|
7297
|
+
bool ConnectUnixSocket(int sock, const char *path)
|
|
7081
7298
|
{
|
|
7082
|
-
struct sockaddr_un
|
|
7299
|
+
struct sockaddr_un sa = {};
|
|
7083
7300
|
|
|
7084
|
-
|
|
7085
|
-
if (!CopyString(path,
|
|
7301
|
+
sa.sun_family = AF_UNIX;
|
|
7302
|
+
if (!CopyString(path, sa.sun_path)) {
|
|
7086
7303
|
LogError("Excessive UNIX socket path length");
|
|
7087
|
-
return
|
|
7304
|
+
return false;
|
|
7088
7305
|
}
|
|
7089
7306
|
|
|
7090
|
-
|
|
7091
|
-
if (sock < 0)
|
|
7092
|
-
return -1;
|
|
7093
|
-
K_DEFER_N(err_guard) { CloseSocket(sock); };
|
|
7094
|
-
|
|
7095
|
-
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
7307
|
+
if (connect(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
|
|
7096
7308
|
#if defined(_WIN32)
|
|
7097
|
-
LogError("Failed to connect to '%1': %2", path, GetWin32ErrorString());
|
|
7098
|
-
return
|
|
7309
|
+
LogError("Failed to connect to UNIX socket '%1': %2", path, GetWin32ErrorString());
|
|
7310
|
+
return false;
|
|
7099
7311
|
#else
|
|
7100
|
-
LogError("Failed to connect to '%1': %2", path, strerror(errno));
|
|
7101
|
-
return
|
|
7312
|
+
LogError("Failed to connect to UNIX socket '%1': %2", path, strerror(errno));
|
|
7313
|
+
return false;
|
|
7102
7314
|
#endif
|
|
7103
7315
|
}
|
|
7104
7316
|
|
|
7105
|
-
|
|
7106
|
-
return sock;
|
|
7317
|
+
return true;
|
|
7107
7318
|
}
|
|
7108
7319
|
|
|
7109
7320
|
void SetDescriptorNonBlock(int fd, bool enable)
|
|
@@ -7613,14 +7824,12 @@ void StreamReader::SetDecoder(StreamDecoder *decoder)
|
|
|
7613
7824
|
this->decoder = decoder;
|
|
7614
7825
|
}
|
|
7615
7826
|
|
|
7616
|
-
bool StreamReader::Open(Span<const uint8_t> buf, const char *filename,
|
|
7617
|
-
CompressionType compression_type)
|
|
7827
|
+
bool StreamReader::Open(Span<const uint8_t> buf, const char *filename, CompressionType compression_type)
|
|
7618
7828
|
{
|
|
7619
7829
|
Close(true);
|
|
7620
7830
|
|
|
7621
7831
|
K_DEFER_N(err_guard) { error = true; };
|
|
7622
7832
|
|
|
7623
|
-
lazy = flags & (int)StreamReaderFlag::LazyFill;
|
|
7624
7833
|
error = false;
|
|
7625
7834
|
raw_read = 0;
|
|
7626
7835
|
read_total = 0;
|
|
@@ -7640,13 +7849,12 @@ bool StreamReader::Open(Span<const uint8_t> buf, const char *filename, unsigned
|
|
|
7640
7849
|
return true;
|
|
7641
7850
|
}
|
|
7642
7851
|
|
|
7643
|
-
bool StreamReader::Open(int fd, const char *filename,
|
|
7852
|
+
bool StreamReader::Open(int fd, const char *filename, CompressionType compression_type)
|
|
7644
7853
|
{
|
|
7645
7854
|
Close(true);
|
|
7646
7855
|
|
|
7647
7856
|
K_DEFER_N(err_guard) { error = true; };
|
|
7648
7857
|
|
|
7649
|
-
lazy = flags & (int)StreamReaderFlag::LazyFill;
|
|
7650
7858
|
error = false;
|
|
7651
7859
|
raw_read = 0;
|
|
7652
7860
|
read_total = 0;
|
|
@@ -7667,13 +7875,12 @@ bool StreamReader::Open(int fd, const char *filename, unsigned int flags, Compre
|
|
|
7667
7875
|
return true;
|
|
7668
7876
|
}
|
|
7669
7877
|
|
|
7670
|
-
OpenResult StreamReader::Open(const char *filename,
|
|
7878
|
+
OpenResult StreamReader::Open(const char *filename, CompressionType compression_type)
|
|
7671
7879
|
{
|
|
7672
7880
|
Close(true);
|
|
7673
7881
|
|
|
7674
7882
|
K_DEFER_N(err_guard) { error = true; };
|
|
7675
7883
|
|
|
7676
|
-
lazy = flags & (int)StreamReaderFlag::LazyFill;
|
|
7677
7884
|
error = false;
|
|
7678
7885
|
raw_read = 0;
|
|
7679
7886
|
read_total = 0;
|
|
@@ -7697,14 +7904,12 @@ OpenResult StreamReader::Open(const char *filename, unsigned int flags, Compress
|
|
|
7697
7904
|
return OpenResult::Success;
|
|
7698
7905
|
}
|
|
7699
7906
|
|
|
7700
|
-
bool StreamReader::Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename,
|
|
7701
|
-
CompressionType compression_type)
|
|
7907
|
+
bool StreamReader::Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename, CompressionType compression_type)
|
|
7702
7908
|
{
|
|
7703
7909
|
Close(true);
|
|
7704
7910
|
|
|
7705
7911
|
K_DEFER_N(err_guard) { error = true; };
|
|
7706
7912
|
|
|
7707
|
-
lazy = flags & (int)StreamReaderFlag::LazyFill;
|
|
7708
7913
|
error = false;
|
|
7709
7914
|
raw_read = 0;
|
|
7710
7915
|
read_total = 0;
|
|
@@ -7748,7 +7953,6 @@ bool StreamReader::Close(bool implicit)
|
|
|
7748
7953
|
bool ret = !filename || !error;
|
|
7749
7954
|
|
|
7750
7955
|
filename = nullptr;
|
|
7751
|
-
lazy = false;
|
|
7752
7956
|
error = true;
|
|
7753
7957
|
source.type = SourceType::Memory;
|
|
7754
7958
|
source.eof = false;
|
|
@@ -7807,6 +8011,40 @@ void StreamReader::SetDescriptorOwned(bool owned)
|
|
|
7807
8011
|
|
|
7808
8012
|
Size StreamReader::Read(Span<uint8_t> out_buf)
|
|
7809
8013
|
{
|
|
8014
|
+
#if !defined(__wasm__)
|
|
8015
|
+
std::lock_guard<std::mutex> lock(mutex);
|
|
8016
|
+
#endif
|
|
8017
|
+
|
|
8018
|
+
if (error) [[unlikely]]
|
|
8019
|
+
return -1;
|
|
8020
|
+
|
|
8021
|
+
Size len = 0;
|
|
8022
|
+
|
|
8023
|
+
if (decoder) {
|
|
8024
|
+
len = decoder->Read(out_buf.len, out_buf.ptr);
|
|
8025
|
+
if (len < 0) [[unlikely]] {
|
|
8026
|
+
error = true;
|
|
8027
|
+
return -1;
|
|
8028
|
+
}
|
|
8029
|
+
} else {
|
|
8030
|
+
len = ReadRaw(out_buf.len, out_buf.ptr);
|
|
8031
|
+
if (len < 0) [[unlikely]]
|
|
8032
|
+
return -1;
|
|
8033
|
+
eof = source.eof;
|
|
8034
|
+
}
|
|
8035
|
+
|
|
8036
|
+
if (!error && read_max >= 0 && len > read_max - read_total) [[unlikely]] {
|
|
8037
|
+
LogError("Exceeded max stream size of %1", FmtDiskSize(read_max));
|
|
8038
|
+
error = true;
|
|
8039
|
+
return -1;
|
|
8040
|
+
}
|
|
8041
|
+
|
|
8042
|
+
read_total += len;
|
|
8043
|
+
return len;
|
|
8044
|
+
}
|
|
8045
|
+
|
|
8046
|
+
Size StreamReader::ReadFill(Span<uint8_t> out_buf)
|
|
8047
|
+
{
|
|
7810
8048
|
#if !defined(__wasm__)
|
|
7811
8049
|
std::lock_guard<std::mutex> lock(mutex);
|
|
7812
8050
|
#endif
|
|
@@ -7842,7 +8080,7 @@ Size StreamReader::Read(Span<uint8_t> out_buf)
|
|
|
7842
8080
|
return -1;
|
|
7843
8081
|
}
|
|
7844
8082
|
|
|
7845
|
-
if (
|
|
8083
|
+
if (eof)
|
|
7846
8084
|
break;
|
|
7847
8085
|
}
|
|
7848
8086
|
|
|
@@ -7883,10 +8121,10 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
|
|
|
7883
8121
|
// who need/want to append a NUL character.
|
|
7884
8122
|
out_buf->Grow((Size)raw_len + 1);
|
|
7885
8123
|
|
|
7886
|
-
Size read_len =
|
|
8124
|
+
Size read_len = ReadFill(out_buf->TakeAvailable());
|
|
7887
8125
|
if (read_len < 0)
|
|
7888
8126
|
return -1;
|
|
7889
|
-
out_buf->len += read_len;
|
|
8127
|
+
out_buf->len += (Size)std::min(raw_len, (int64_t)read_len);
|
|
7890
8128
|
|
|
7891
8129
|
buf_guard.Disable();
|
|
7892
8130
|
return read_len;
|
|
@@ -7897,7 +8135,7 @@ Size StreamReader::ReadAll(Size max_len, HeapArray<uint8_t> *out_buf)
|
|
|
7897
8135
|
Size grow = std::min(total_len ? Megabytes(1) : Kibibytes(64), K_SIZE_MAX - out_buf->len);
|
|
7898
8136
|
out_buf->Grow(grow);
|
|
7899
8137
|
|
|
7900
|
-
Size read_len = Read(out_buf->
|
|
8138
|
+
Size read_len = Read(out_buf->TakeAvailable());
|
|
7901
8139
|
if (read_len < 0)
|
|
7902
8140
|
return -1;
|
|
7903
8141
|
|
|
@@ -8032,7 +8270,9 @@ bool LineReader::Next(Span<char> *out_line)
|
|
|
8032
8270
|
if (!view.len) {
|
|
8033
8271
|
buf.Grow(K_LINE_READER_STEP_SIZE + 1);
|
|
8034
8272
|
|
|
8035
|
-
|
|
8273
|
+
Span<char> available = MakeSpan(buf.end(), K_LINE_READER_STEP_SIZE);
|
|
8274
|
+
|
|
8275
|
+
Size read_len = st->Read(available);
|
|
8036
8276
|
if (read_len < 0) {
|
|
8037
8277
|
error = true;
|
|
8038
8278
|
return false;
|
|
@@ -8960,7 +9200,7 @@ bool PatchFile(Span<const uint8_t> data, StreamWriter *writer,
|
|
|
8960
9200
|
bool PatchFile(const AssetInfo &asset, StreamWriter *writer,
|
|
8961
9201
|
FunctionRef<void(Span<const char>, StreamWriter *)> func)
|
|
8962
9202
|
{
|
|
8963
|
-
StreamReader reader(asset.data, "<asset>",
|
|
9203
|
+
StreamReader reader(asset.data, "<asset>", asset.compression_type);
|
|
8964
9204
|
|
|
8965
9205
|
if (!PatchFile(&reader, writer, func)) {
|
|
8966
9206
|
K_ASSERT(reader.IsValid());
|
|
@@ -9509,6 +9749,10 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
|
|
|
9509
9749
|
Delete(str_offset, SkipForward(str_offset, 1));
|
|
9510
9750
|
RenderRaw();
|
|
9511
9751
|
}
|
|
9752
|
+
} else if (match_escape("\x1B")) { // Double escape
|
|
9753
|
+
StdErr->Write("\r\n");
|
|
9754
|
+
StdErr->Flush();
|
|
9755
|
+
return false;
|
|
9512
9756
|
} else if (match_escape("\x7F")) { // Alt-Backspace
|
|
9513
9757
|
Delete(FindBackward(str_offset, " \t\r\n"), str_offset);
|
|
9514
9758
|
RenderRaw();
|
|
@@ -9651,11 +9895,54 @@ bool ConsolePrompter::ReadRaw(Span<const char> *out_str)
|
|
|
9651
9895
|
return true;
|
|
9652
9896
|
} break;
|
|
9653
9897
|
|
|
9898
|
+
case '\t': {
|
|
9899
|
+
if (complete) {
|
|
9900
|
+
BlockAllocator temp_alloc;
|
|
9901
|
+
HeapArray<CompleteChoice> choices;
|
|
9902
|
+
|
|
9903
|
+
PushLogFilter([](LogLevel, const char *, const char *, FunctionRef<LogFunc>) {});
|
|
9904
|
+
K_DEFER_N(log_guard) { PopLogFilter(); };
|
|
9905
|
+
|
|
9906
|
+
CompleteResult ret = complete(str, &temp_alloc, &choices);
|
|
9907
|
+
|
|
9908
|
+
switch (ret) {
|
|
9909
|
+
case CompleteResult::Success: {
|
|
9910
|
+
if (choices.len == 1) {
|
|
9911
|
+
const CompleteChoice &choice = choices[0];
|
|
9912
|
+
|
|
9913
|
+
str.RemoveFrom(0);
|
|
9914
|
+
str.Append(choice.value);
|
|
9915
|
+
str_offset = str.len;
|
|
9916
|
+
RenderRaw();
|
|
9917
|
+
} else if (choices.len) {
|
|
9918
|
+
for (const CompleteChoice &choice: choices) {
|
|
9919
|
+
Print(StdErr, "\r\n %!0%!Y..%1%!0", choice.name);
|
|
9920
|
+
}
|
|
9921
|
+
StdErr->Write("\r\n");
|
|
9922
|
+
|
|
9923
|
+
RenderRaw();
|
|
9924
|
+
}
|
|
9925
|
+
} break;
|
|
9926
|
+
|
|
9927
|
+
case CompleteResult::TooMany: {
|
|
9928
|
+
Print(StdErr, "\r\n %!0%!Y..%1%!0\r\n", T("Too many possibilities to show"));
|
|
9929
|
+
RenderRaw();
|
|
9930
|
+
} break;
|
|
9931
|
+
case CompleteResult::Error: {
|
|
9932
|
+
Print(StdErr, "\r\n %!0%!Y..%1%!0\r\n", T("Autocompletion error"));
|
|
9933
|
+
RenderRaw();
|
|
9934
|
+
} break;
|
|
9935
|
+
}
|
|
9936
|
+
|
|
9937
|
+
break;
|
|
9938
|
+
}
|
|
9939
|
+
} [[fallthrough]];
|
|
9940
|
+
|
|
9654
9941
|
default: {
|
|
9655
9942
|
LocalArray<char, 16> frag;
|
|
9656
9943
|
if (uc == '\t') {
|
|
9657
9944
|
frag.Append(" ");
|
|
9658
|
-
} else if (uc
|
|
9945
|
+
} else if (!IsAsciiControl(uc)) {
|
|
9659
9946
|
frag.len = EncodeUtf8(uc, frag.data);
|
|
9660
9947
|
} else {
|
|
9661
9948
|
continue;
|
|
@@ -9731,6 +10018,14 @@ Size ConsolePrompter::ReadRawEnum(Span<const PromptChoice> choices, Size value)
|
|
|
9731
10018
|
fake_input = "\x10";
|
|
9732
10019
|
} else if (match_escape("[B")) { // Down
|
|
9733
10020
|
fake_input = "\x0E";
|
|
10021
|
+
} else if (match_escape("\x1B")) { // Double escape
|
|
10022
|
+
if (rows > y) {
|
|
10023
|
+
Print(StdErr, "\x1B[%1B", rows - y);
|
|
10024
|
+
}
|
|
10025
|
+
StdErr->Write("\r");
|
|
10026
|
+
StdErr->Flush();
|
|
10027
|
+
|
|
10028
|
+
return -1;
|
|
9734
10029
|
}
|
|
9735
10030
|
} break;
|
|
9736
10031
|
|
|
@@ -9792,7 +10087,7 @@ bool ConsolePrompter::ReadBuffered(Span<const char> *out_str)
|
|
|
9792
10087
|
|
|
9793
10088
|
do {
|
|
9794
10089
|
uint8_t c = 0;
|
|
9795
|
-
if (StdIn->Read(
|
|
10090
|
+
if (StdIn->Read(MakeSpan(&c, 1)) < 0)
|
|
9796
10091
|
return false;
|
|
9797
10092
|
|
|
9798
10093
|
if (c == '\n') {
|
|
@@ -9801,7 +10096,7 @@ bool ConsolePrompter::ReadBuffered(Span<const char> *out_str)
|
|
|
9801
10096
|
*out_str = str;
|
|
9802
10097
|
}
|
|
9803
10098
|
return true;
|
|
9804
|
-
} else if (c
|
|
10099
|
+
} else if (!IsAsciiControl(c)) {
|
|
9805
10100
|
str.Append((char)c);
|
|
9806
10101
|
}
|
|
9807
10102
|
} while (!StdIn->IsEOF());
|
|
@@ -9823,7 +10118,7 @@ Size ConsolePrompter::ReadBufferedEnum(Span<const PromptChoice> choices)
|
|
|
9823
10118
|
|
|
9824
10119
|
do {
|
|
9825
10120
|
uint8_t c = 0;
|
|
9826
|
-
if (StdIn->Read(
|
|
10121
|
+
if (StdIn->Read(MakeSpan(&c, 1)) < 0)
|
|
9827
10122
|
return -1;
|
|
9828
10123
|
|
|
9829
10124
|
if (c == '\n') {
|
|
@@ -9840,7 +10135,7 @@ Size ConsolePrompter::ReadBufferedEnum(Span<const PromptChoice> choices)
|
|
|
9840
10135
|
|
|
9841
10136
|
StdErr->Write(prefix);
|
|
9842
10137
|
StdErr->Flush();
|
|
9843
|
-
} else if (c
|
|
10138
|
+
} else if (!IsAsciiControl(c)) {
|
|
9844
10139
|
str.Append((char)c);
|
|
9845
10140
|
}
|
|
9846
10141
|
} while (!StdIn->IsEOF());
|
|
@@ -9944,7 +10239,11 @@ void ConsolePrompter::FormatChoices(Span<const PromptChoice> choices, Size value
|
|
|
9944
10239
|
const PromptChoice &choice = choices[i];
|
|
9945
10240
|
int pad = align - ComputeUnicodeWidth(choice.str);
|
|
9946
10241
|
|
|
9947
|
-
|
|
10242
|
+
if (choice.c) {
|
|
10243
|
+
Fmt(&str, " [%1] %2%3 ", choice.c, choice.str, FmtRepeat(" ", pad));
|
|
10244
|
+
} else {
|
|
10245
|
+
Fmt(&str, " %1%2 ", choice.str, FmtRepeat(" ", pad));
|
|
10246
|
+
}
|
|
9948
10247
|
if (i == value) {
|
|
9949
10248
|
str_offset = str.len;
|
|
9950
10249
|
}
|
|
@@ -9984,7 +10283,7 @@ void ConsolePrompter::RenderRaw()
|
|
|
9984
10283
|
int width = mask ? mask_columns : ComputeUnicodeWidth(str.Take(i, bytes));
|
|
9985
10284
|
|
|
9986
10285
|
if (x2 + width >= columns || str[i] == '\n') {
|
|
9987
|
-
FmtArg prefix =
|
|
10286
|
+
FmtArg prefix = FmtRepeat(" ", prompt_columns - 1);
|
|
9988
10287
|
Print(StdErr, "\x1B[0K\r\n%!D.+%1%!0 %!..+", prefix);
|
|
9989
10288
|
|
|
9990
10289
|
x2 = prompt_columns;
|
|
@@ -10028,7 +10327,7 @@ void ConsolePrompter::RenderBuffered()
|
|
|
10028
10327
|
Print(StdErr, "%1 %2", prompt, line);
|
|
10029
10328
|
while (remain.len) {
|
|
10030
10329
|
line = SplitStr(remain, '\n', &remain);
|
|
10031
|
-
Print(StdErr, "\n%1%2",
|
|
10330
|
+
Print(StdErr, "\n%1%2", FmtRepeat(" ", prompt_columns), line);
|
|
10032
10331
|
}
|
|
10033
10332
|
|
|
10034
10333
|
StdErr->Flush();
|
|
@@ -10206,6 +10505,7 @@ const char *Prompt(const char *prompt, const char *default_value, const char *ma
|
|
|
10206
10505
|
|
|
10207
10506
|
prompter.prompt = prompt;
|
|
10208
10507
|
prompter.mask = mask;
|
|
10508
|
+
|
|
10209
10509
|
prompter.str.allocator = alloc;
|
|
10210
10510
|
if (default_value) {
|
|
10211
10511
|
prompter.str.Append(default_value);
|
|
@@ -10225,11 +10525,12 @@ Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value
|
|
|
10225
10525
|
HashSet<char> keys;
|
|
10226
10526
|
|
|
10227
10527
|
for (const PromptChoice &choice: choices) {
|
|
10228
|
-
|
|
10229
|
-
|
|
10528
|
+
if (!choice.c)
|
|
10529
|
+
continue;
|
|
10230
10530
|
|
|
10231
|
-
|
|
10232
|
-
|
|
10531
|
+
bool duplicates = !keys.InsertOrFail(choice.c);
|
|
10532
|
+
K_ASSERT(!duplicates);
|
|
10533
|
+
}
|
|
10233
10534
|
}
|
|
10234
10535
|
#endif
|
|
10235
10536
|
|
|
@@ -10242,13 +10543,12 @@ Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value
|
|
|
10242
10543
|
Size PromptEnum(const char *prompt, Span<const char *const> strings, Size value)
|
|
10243
10544
|
{
|
|
10244
10545
|
static const char literals[] = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
10245
|
-
K_ASSERT(strings.len <= K_LEN(literals));
|
|
10246
10546
|
|
|
10247
10547
|
HeapArray<PromptChoice> choices;
|
|
10248
10548
|
|
|
10249
10549
|
for (Size i = 0; i < strings.len; i++) {
|
|
10250
10550
|
const char *str = strings[i];
|
|
10251
|
-
PromptChoice choice = { literals[i]
|
|
10551
|
+
PromptChoice choice = { str, i < K_LEN(literals) ? literals[i] : (char)0 };
|
|
10252
10552
|
|
|
10253
10553
|
choices.Append(choice);
|
|
10254
10554
|
}
|
|
@@ -10256,6 +10556,134 @@ Size PromptEnum(const char *prompt, Span<const char *const> strings, Size value)
|
|
|
10256
10556
|
return PromptEnum(prompt, choices, value);
|
|
10257
10557
|
}
|
|
10258
10558
|
|
|
10559
|
+
int PromptYN(const char *prompt)
|
|
10560
|
+
{
|
|
10561
|
+
const char *yes = T("Yes");
|
|
10562
|
+
const char *no = T("No");
|
|
10563
|
+
|
|
10564
|
+
const char *shortcuts = T("yn");
|
|
10565
|
+
K_ASSERT(strlen(shortcuts) == 2);
|
|
10566
|
+
|
|
10567
|
+
Size ret = PromptEnum(prompt, {{ yes, shortcuts[0] }, { no, shortcuts[1] }});
|
|
10568
|
+
if (ret < 0)
|
|
10569
|
+
return -1;
|
|
10570
|
+
|
|
10571
|
+
return !ret;
|
|
10572
|
+
}
|
|
10573
|
+
|
|
10574
|
+
const char *PromptPath(const char *prompt, const char *default_path, Span<const char> root_directory, Allocator *alloc)
|
|
10575
|
+
{
|
|
10576
|
+
K_ASSERT(alloc);
|
|
10577
|
+
|
|
10578
|
+
ConsolePrompter prompter;
|
|
10579
|
+
|
|
10580
|
+
prompter.prompt = prompt;
|
|
10581
|
+
prompter.complete = [&](Span<const char> str, Allocator *alloc, HeapArray<CompleteChoice> *out_choices) {
|
|
10582
|
+
Size start_len = out_choices->len;
|
|
10583
|
+
K_DEFER_N(err_guard) { out_choices->RemoveFrom(start_len); };
|
|
10584
|
+
|
|
10585
|
+
Span<const char> path = TrimStrRight(str, K_PATH_SEPARATORS);
|
|
10586
|
+
bool separator = (path.len < str.len);
|
|
10587
|
+
|
|
10588
|
+
// If the value points to a directory, append separator and return
|
|
10589
|
+
if (str.len && !separator) {
|
|
10590
|
+
const char *filename = NormalizePath(path, root_directory, alloc).ptr;
|
|
10591
|
+
|
|
10592
|
+
FileInfo file_info;
|
|
10593
|
+
StatResult ret = StatFile(filename, (int)StatFlag::SilentMissing | (int)StatFlag::FollowSymlink, &file_info);
|
|
10594
|
+
|
|
10595
|
+
if (ret == StatResult::Success && file_info.type == FileType::Directory) {
|
|
10596
|
+
const char *value = Fmt(alloc, "%1%/", path).ptr;
|
|
10597
|
+
out_choices->Append({ value, value });
|
|
10598
|
+
|
|
10599
|
+
err_guard.Disable();
|
|
10600
|
+
return CompleteResult::Success;
|
|
10601
|
+
}
|
|
10602
|
+
}
|
|
10603
|
+
|
|
10604
|
+
Span<const char> directory = path;
|
|
10605
|
+
Span<const char> prefix = separator ? "" : SplitStrReverseAny(path, K_PATH_SEPARATORS, &directory);
|
|
10606
|
+
|
|
10607
|
+
// EnumerateDirectory takes a C string, so we need the NUL terminator,
|
|
10608
|
+
// and we also need to take root_dir into account.
|
|
10609
|
+
const char *dirname = nullptr;
|
|
10610
|
+
|
|
10611
|
+
if (PathIsAbsolute(directory)) {
|
|
10612
|
+
dirname = DuplicateString(directory, alloc).ptr;
|
|
10613
|
+
} else {
|
|
10614
|
+
if (!root_directory.len)
|
|
10615
|
+
return CompleteResult::Success;
|
|
10616
|
+
|
|
10617
|
+
dirname = NormalizePath(directory, root_directory, alloc).ptr;
|
|
10618
|
+
dirname = dirname[0] ? dirname : ".";
|
|
10619
|
+
}
|
|
10620
|
+
|
|
10621
|
+
EnumResult ret = EnumerateDirectory(dirname, nullptr, -1, [&](const char *basename, FileType file_type) {
|
|
10622
|
+
#if defined(_WIN32)
|
|
10623
|
+
if (!StartsWithI(basename, prefix))
|
|
10624
|
+
return true;
|
|
10625
|
+
#else
|
|
10626
|
+
if (!StartsWith(basename, prefix))
|
|
10627
|
+
return true;
|
|
10628
|
+
#endif
|
|
10629
|
+
|
|
10630
|
+
if (out_choices->len - start_len >= K_COMPLETE_PATH_LIMIT)
|
|
10631
|
+
return false;
|
|
10632
|
+
|
|
10633
|
+
CompleteChoice choice;
|
|
10634
|
+
{
|
|
10635
|
+
HeapArray<char> buf(alloc);
|
|
10636
|
+
|
|
10637
|
+
// Make directory part
|
|
10638
|
+
buf.Append(directory);
|
|
10639
|
+
if (directory.len && !IsPathSeparator(directory[directory.len - 1])) {
|
|
10640
|
+
buf.Append(*K_PATH_SEPARATORS);
|
|
10641
|
+
}
|
|
10642
|
+
|
|
10643
|
+
Size name_offset = buf.len;
|
|
10644
|
+
|
|
10645
|
+
// Append name
|
|
10646
|
+
buf.Append(basename);
|
|
10647
|
+
if (file_type == FileType::Directory) {
|
|
10648
|
+
buf.Append(*K_PATH_SEPARATORS);
|
|
10649
|
+
}
|
|
10650
|
+
buf.Append(0);
|
|
10651
|
+
buf.Trim();
|
|
10652
|
+
|
|
10653
|
+
choice.value = buf.Leak().ptr;
|
|
10654
|
+
choice.name = choice.value + name_offset;
|
|
10655
|
+
}
|
|
10656
|
+
|
|
10657
|
+
out_choices->Append(choice);
|
|
10658
|
+
return true;
|
|
10659
|
+
});
|
|
10660
|
+
|
|
10661
|
+
if (ret == EnumResult::CallbackFail) {
|
|
10662
|
+
return CompleteResult::TooMany;
|
|
10663
|
+
} else if (ret != EnumResult::Success) {
|
|
10664
|
+
// Just ignore it and don't print anything
|
|
10665
|
+
return CompleteResult::Success;
|
|
10666
|
+
}
|
|
10667
|
+
|
|
10668
|
+
std::sort(out_choices->ptr + start_len, out_choices->end(),
|
|
10669
|
+
[](const CompleteChoice &choice1, const CompleteChoice &choice2) { return CmpNaturalI(choice1.name, choice2.name) < 0; });
|
|
10670
|
+
|
|
10671
|
+
err_guard.Disable();
|
|
10672
|
+
return CompleteResult::Success;
|
|
10673
|
+
};
|
|
10674
|
+
|
|
10675
|
+
prompter.str.allocator = alloc;
|
|
10676
|
+
if (default_path) {
|
|
10677
|
+
prompter.str.Append(default_path);
|
|
10678
|
+
}
|
|
10679
|
+
|
|
10680
|
+
if (!prompter.Read())
|
|
10681
|
+
return nullptr;
|
|
10682
|
+
|
|
10683
|
+
const char *str = NormalizePath(prompter.str, alloc).ptr;
|
|
10684
|
+
return str;
|
|
10685
|
+
}
|
|
10686
|
+
|
|
10259
10687
|
// ------------------------------------------------------------------------
|
|
10260
10688
|
// Mime types
|
|
10261
10689
|
// ------------------------------------------------------------------------
|
|
@@ -10373,7 +10801,7 @@ static inline int ComputeCharacterWidth(int32_t uc)
|
|
|
10373
10801
|
{
|
|
10374
10802
|
// Fast path
|
|
10375
10803
|
if (uc < 128)
|
|
10376
|
-
return (uc
|
|
10804
|
+
return IsAsciiControl(uc) ? 0 : 1;
|
|
10377
10805
|
|
|
10378
10806
|
if (TestUnicodeTable(WcWidthNull, uc))
|
|
10379
10807
|
return 0;
|