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.
Files changed (102) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build/koffi/darwin_arm64/koffi.node +0 -0
  3. package/build/koffi/darwin_x64/koffi.node +0 -0
  4. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  5. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  6. package/build/koffi/freebsd_x64/koffi.node +0 -0
  7. package/build/koffi/linux_arm64/koffi.node +0 -0
  8. package/build/koffi/linux_armhf/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_loong64/koffi.node +0 -0
  11. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  12. package/build/koffi/linux_x64/koffi.node +0 -0
  13. package/build/koffi/musl_arm64/koffi.node +0 -0
  14. package/build/koffi/musl_x64/koffi.node +0 -0
  15. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  16. package/build/koffi/openbsd_x64/koffi.node +0 -0
  17. package/build/koffi/win32_arm64/koffi.node +0 -0
  18. package/build/koffi/win32_ia32/koffi.node +0 -0
  19. package/build/koffi/win32_x64/koffi.node +0 -0
  20. package/doc/assets.ini +2 -1
  21. package/doc/build.sh +9 -0
  22. package/doc/pages/404.md +17 -0
  23. package/doc/pages/index.md +1 -1
  24. package/doc/pages/misc.md +16 -11
  25. package/doc/pages.ini +4 -0
  26. package/doc/static/highlight.js +2 -14
  27. package/doc/static/koffi.css +3 -15
  28. package/doc/static/print.css +2 -14
  29. package/index.d.ts +29 -24
  30. package/index.js +8 -8
  31. package/indirect.js +8 -8
  32. package/{src/core → lib/native}/base/base.cc +1058 -630
  33. package/{src/core → lib/native}/base/base.hh +334 -165
  34. package/{src/core → lib/native}/base/crc.inc +2 -20
  35. package/lib/native/base/crc_gen.py +72 -0
  36. package/{src/core → lib/native}/base/mimetypes.inc +2 -20
  37. package/{src/core → lib/native}/base/mimetypes_gen.py +2 -21
  38. package/lib/native/base/tower.cc +821 -0
  39. package/lib/native/base/tower.hh +81 -0
  40. package/{src/core → lib/native}/base/unicode.inc +2 -20
  41. package/{src/core → lib/native}/base/unicode_gen.py +4 -41
  42. package/package.json +1 -1
  43. package/src/cnoke/assets/FindCNoke.cmake +8 -20
  44. package/src/cnoke/assets/win_delay_hook.c +2 -20
  45. package/src/cnoke/cnoke.js +2 -21
  46. package/src/cnoke/src/builder.js +2 -20
  47. package/src/cnoke/src/index.js +2 -20
  48. package/src/cnoke/src/tools.js +2 -20
  49. package/src/koffi/CMakeLists.txt +19 -22
  50. package/src/koffi/cmake/raylib.cmake +5 -22
  51. package/src/koffi/cmake/sqlite3.cmake +2 -20
  52. package/src/koffi/src/abi_arm32.cc +7 -25
  53. package/src/koffi/src/abi_arm32_asm.S +2 -20
  54. package/src/koffi/src/abi_arm64.cc +7 -25
  55. package/src/koffi/src/abi_arm64_asm.S +2 -20
  56. package/src/koffi/src/abi_arm64_asm.asm +2 -20
  57. package/src/koffi/src/abi_loong64.cc +2 -20
  58. package/src/koffi/src/abi_loong64_asm.S +2 -20
  59. package/src/koffi/src/abi_riscv64.cc +7 -25
  60. package/src/koffi/src/abi_riscv64_asm.S +2 -20
  61. package/src/koffi/src/abi_x64_sysv.cc +7 -25
  62. package/src/koffi/src/abi_x64_sysv_asm.S +2 -20
  63. package/src/koffi/src/abi_x64_win.cc +12 -30
  64. package/src/koffi/src/abi_x64_win_asm.asm +2 -20
  65. package/src/koffi/src/abi_x86.cc +7 -25
  66. package/src/koffi/src/abi_x86_asm.S +2 -20
  67. package/src/koffi/src/abi_x86_asm.asm +2 -20
  68. package/src/koffi/src/call.cc +25 -45
  69. package/src/koffi/src/call.hh +3 -21
  70. package/src/koffi/src/errno.inc +2 -20
  71. package/src/koffi/src/ffi.cc +62 -62
  72. package/src/koffi/src/ffi.hh +14 -29
  73. package/src/koffi/src/init.js +2 -20
  74. package/src/koffi/src/parser.cc +13 -27
  75. package/src/koffi/src/parser.hh +3 -21
  76. package/src/koffi/src/trampolines/armasm.inc +0 -21
  77. package/src/koffi/src/trampolines/gnu.inc +0 -21
  78. package/src/koffi/src/trampolines/masm32.inc +0 -21
  79. package/src/koffi/src/trampolines/masm64.inc +0 -21
  80. package/src/koffi/src/trampolines/prototypes.inc +0 -21
  81. package/src/koffi/src/util.cc +44 -59
  82. package/src/koffi/src/util.hh +6 -24
  83. package/src/koffi/src/uv.cc +193 -0
  84. package/src/koffi/src/uv.def +10 -0
  85. package/src/koffi/src/uv.hh +40 -0
  86. package/src/koffi/src/win32.cc +2 -20
  87. package/src/koffi/src/win32.hh +3 -21
  88. package/vendor/node-api-headers/include/uv/aix.h +32 -0
  89. package/vendor/node-api-headers/include/uv/bsd.h +34 -0
  90. package/vendor/node-api-headers/include/uv/darwin.h +61 -0
  91. package/vendor/node-api-headers/include/uv/errno.h +483 -0
  92. package/vendor/node-api-headers/include/uv/linux.h +34 -0
  93. package/vendor/node-api-headers/include/uv/os390.h +33 -0
  94. package/vendor/node-api-headers/include/uv/posix.h +31 -0
  95. package/vendor/node-api-headers/include/uv/sunos.h +44 -0
  96. package/vendor/node-api-headers/include/uv/threadpool.h +37 -0
  97. package/vendor/node-api-headers/include/uv/tree.h +521 -0
  98. package/vendor/node-api-headers/include/uv/unix.h +512 -0
  99. package/vendor/node-api-headers/include/uv/version.h +43 -0
  100. package/vendor/node-api-headers/include/uv/win.h +698 -0
  101. package/vendor/node-api-headers/include/uv.h +1990 -0
  102. package/src/core/base/crc_gen.py +0 -109
@@ -1,23 +1,5 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
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
  #pragma once
23
5
 
@@ -108,6 +90,8 @@ namespace K {
108
90
  #define K_PROGRESS_USED_NODES 100
109
91
  #define K_PROGRESS_TEXT_SIZE 64
110
92
 
93
+ #define K_COMPLETE_PATH_LIMIT 256
94
+
111
95
  // ------------------------------------------------------------------------
112
96
  // Utility
113
97
  // ------------------------------------------------------------------------
@@ -1584,6 +1568,47 @@ static inline bool StartsWith(const char *str, const char *prefix)
1584
1568
  return !prefix[i];
1585
1569
  }
1586
1570
 
1571
+ static inline bool StartsWithI(Span<const char> str, Span<const char> prefix)
1572
+ {
1573
+ Size i = 0;
1574
+ while (i < str.len && i < prefix.len) {
1575
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1576
+ return false;
1577
+ i++;
1578
+ }
1579
+ return (i == prefix.len);
1580
+ }
1581
+ static inline bool StartsWithI(Span<const char> str, const char *prefix)
1582
+ {
1583
+ Size i = 0;
1584
+ while (i < str.len && prefix[i]) {
1585
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1586
+ return false;
1587
+ i++;
1588
+ }
1589
+ return !prefix[i];
1590
+ }
1591
+ static inline bool StartsWithI(const char *str, Span<const char> prefix)
1592
+ {
1593
+ Size i = 0;
1594
+ while (str[i] && i < prefix.len) {
1595
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1596
+ return false;
1597
+ i++;
1598
+ }
1599
+ return (i == prefix.len);
1600
+ }
1601
+ static inline bool StartsWithI(const char *str, const char *prefix)
1602
+ {
1603
+ Size i = 0;
1604
+ while (str[i] && prefix[i]) {
1605
+ if (LowerAscii(str[i]) != LowerAscii(prefix[i]))
1606
+ return false;
1607
+ i++;
1608
+ }
1609
+ return !prefix[i];
1610
+ }
1611
+
1587
1612
  static inline bool EndsWith(Span<const char> str, Span<const char> suffix)
1588
1613
  {
1589
1614
  Size i = str.len - 1;
@@ -1599,6 +1624,21 @@ static inline bool EndsWith(Span<const char> str, Span<const char> suffix)
1599
1624
 
1600
1625
  return j < 0;
1601
1626
  }
1627
+ static inline bool EndsWithI(Span<const char> str, Span<const char> suffix)
1628
+ {
1629
+ Size i = str.len - 1;
1630
+ Size j = suffix.len - 1;
1631
+
1632
+ while (i >= 0 && j >= 0) {
1633
+ if (LowerAscii(str[i]) != LowerAscii(suffix[j]))
1634
+ return false;
1635
+
1636
+ i--;
1637
+ j--;
1638
+ }
1639
+
1640
+ return j < 0;
1641
+ }
1602
1642
 
1603
1643
  static inline Size FindStr(Span<const char> str, Span<const char> needle)
1604
1644
  {
@@ -1902,6 +1942,9 @@ static inline Span<const char> TrimStrRight(Span<const char> str, const char *tr
1902
1942
  static inline Span<const char> TrimStr(Span<const char> str, const char *trim_chars = " \t\r\n")
1903
1943
  { return TrimStr(MakeSpan((char *)str.ptr, str.len), trim_chars); }
1904
1944
 
1945
+ int CmpNatural(Span<const char> str1, Span<const char> str2);
1946
+ int CmpNaturalI(Span<const char> str1, Span<const char> str2);
1947
+
1905
1948
  // ------------------------------------------------------------------------
1906
1949
  // Collections
1907
1950
  // ------------------------------------------------------------------------
@@ -2787,7 +2830,7 @@ public:
2787
2830
  return ptr;
2788
2831
  }
2789
2832
 
2790
- ValueType *TrySet(const ValueType &value, bool *out_inserted = nullptr)
2833
+ ValueType *InsertOrGet(const ValueType &value, bool *out_inserted = nullptr)
2791
2834
  {
2792
2835
  const KeyType &key = Handler::GetKey(value);
2793
2836
 
@@ -2803,7 +2846,7 @@ public:
2803
2846
  }
2804
2847
  return ptr;
2805
2848
  }
2806
- ValueType *TrySetDefault(const KeyType &key, bool *out_inserted = nullptr)
2849
+ ValueType *InsertOrGetDefault(const KeyType &key, bool *out_inserted = nullptr)
2807
2850
  {
2808
2851
  bool inserted;
2809
2852
  ValueType *ptr = Insert(key, &inserted);
@@ -3247,15 +3290,15 @@ public:
3247
3290
  return table_it;
3248
3291
  }
3249
3292
 
3250
- ValueType *TrySet(const KeyType &key, const ValueType &value, bool *out_inserted = nullptr)
3293
+ ValueType *InsertOrGet(const KeyType &key, const ValueType &value, bool *out_inserted = nullptr)
3251
3294
  {
3252
- Bucket *ptr = table.TrySet({ key, value }, out_inserted);
3295
+ Bucket *ptr = table.InsertOrGet({ key, value }, out_inserted);
3253
3296
  return &ptr->value;
3254
3297
  }
3255
- Bucket *TrySetDefault(const KeyType &key, bool *out_inserted = nullptr)
3298
+ Bucket *InsertOrGetDefault(const KeyType &key, bool *out_inserted = nullptr)
3256
3299
  {
3257
3300
  bool inserted;
3258
- Bucket *ptr = table.TrySetDefault(key, &inserted);
3301
+ Bucket *ptr = table.InsertOrGetDefault(key, &inserted);
3259
3302
 
3260
3303
  if (inserted) {
3261
3304
  ptr->key = key;
@@ -3318,14 +3361,23 @@ public:
3318
3361
  { return table.FindValue(value, default_value); }
3319
3362
 
3320
3363
  ValueType *Set(const ValueType &value) { return table.Set(value); }
3321
- ValueType *TrySet(const ValueType &value, bool *out_inserted = nullptr)
3322
- { return table.TrySet(value, out_inserted); }
3364
+
3365
+ ValueType *InsertOrGet(const ValueType &value, bool *out_inserted = nullptr)
3366
+ { return table.InsertOrGet(value, out_inserted); }
3367
+ bool InsertOrFail(const ValueType &value)
3368
+ {
3369
+ bool inserted;
3370
+ InsertOrGet(value, &inserted);
3371
+ return inserted;
3372
+ }
3323
3373
 
3324
3374
  void Remove(ValueType *it) { table.Remove(it); }
3325
3375
  template <typename T = ValueType>
3326
3376
  void Remove(const T &value) { Remove(Find(value)); }
3327
3377
 
3328
3378
  void Trim() { table.Trim(); }
3379
+
3380
+ private:
3329
3381
  };
3330
3382
 
3331
3383
  // XXX: Switch to perfect hashing later on
@@ -3552,6 +3604,13 @@ static inline int64_t GetClockCounter()
3552
3604
  int64_t counter = ((int64_t)counter_high << 32) | counter_low;
3553
3605
  return counter;
3554
3606
  }
3607
+ #elif defined(__aarch64__)
3608
+ static inline int64_t GetClockCounter()
3609
+ {
3610
+ uint64_t counter;
3611
+ __asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r" (counter));
3612
+ return counter;
3613
+ }
3555
3614
  #endif
3556
3615
 
3557
3616
  struct TimeSpec {
@@ -3577,10 +3636,11 @@ int64_t ComposeTimeUTC(const TimeSpec &spec);
3577
3636
  // ------------------------------------------------------------------------
3578
3637
 
3579
3638
  enum class FmtType {
3580
- Str1,
3581
- Str2,
3582
- Buffer,
3639
+ Str,
3640
+ PadStr,
3641
+ RepeatStr,
3583
3642
  Char,
3643
+ Buffer,
3584
3644
  Custom,
3585
3645
  Bool,
3586
3646
  Integer,
@@ -3591,15 +3651,19 @@ enum class FmtType {
3591
3651
  Octal,
3592
3652
  BigHex,
3593
3653
  SmallHex,
3654
+ BigBytes,
3655
+ SmallBytes,
3594
3656
  MemorySize,
3595
3657
  DiskSize,
3596
3658
  Date,
3597
3659
  TimeISO,
3598
3660
  TimeNice,
3599
- Random,
3661
+ List,
3600
3662
  FlagNames,
3601
3663
  FlagOptions,
3602
- Span
3664
+ Random,
3665
+ SafeStr,
3666
+ SafeChar
3603
3667
  };
3604
3668
 
3605
3669
  template <typename T>
@@ -3649,14 +3713,18 @@ class FmtArg {
3649
3713
  public:
3650
3714
  FmtType type;
3651
3715
  union {
3652
- const char *str1;
3653
- Span<const char> str2;
3716
+ Span<const char> str;
3717
+ struct {
3718
+ const char *str;
3719
+ int count;
3720
+ } repeat;
3654
3721
  char buf[32];
3655
3722
  char ch;
3656
3723
  FmtCustom custom;
3657
3724
  bool b;
3658
3725
  int64_t i;
3659
3726
  uint64_t u;
3727
+ Span<const uint8_t> hex;
3660
3728
  struct {
3661
3729
  float value;
3662
3730
  int min_prec;
@@ -3684,68 +3752,123 @@ public:
3684
3752
  Span<const struct OptionDesc> options;
3685
3753
  } u;
3686
3754
  const char *separator;
3687
- } flags;
3688
-
3689
- struct {
3690
- FmtType type;
3691
- int type_len;
3692
- const void *ptr;
3693
- Size len;
3694
- const char *separator;
3695
- } span;
3755
+ } list;
3696
3756
  } u;
3697
3757
 
3698
- int repeat = 1;
3699
- int pad_len = 0;
3700
- char pad_char = 0;
3758
+ int pad = 0;
3759
+ char padding = 0;
3701
3760
 
3702
3761
  FmtArg() = default;
3703
- FmtArg(std::nullptr_t) : type(FmtType::Str1) { u.str1 = "(null)"; }
3704
- FmtArg(const char *str) : type(FmtType::Str1) { u.str1 = str ? str : "(null)"; }
3705
- FmtArg(Span<const char> str) : type(FmtType::Str2) { u.str2 = str; }
3706
- FmtArg(char c) : type(FmtType::Char) { u.ch = c; }
3707
- FmtArg(const FmtCustom &custom) : type(FmtType::Custom) { u.custom = custom; }
3708
- FmtArg(bool b) : type(FmtType::Bool) { u.b = b; }
3709
- FmtArg(unsigned char i) : type(FmtType::Unsigned) { u.u = i; }
3710
- FmtArg(short i) : type(FmtType::Integer) { u.i = i; }
3711
- FmtArg(unsigned short i) : type(FmtType::Unsigned) { u.u = i; }
3712
- FmtArg(int i) : type(FmtType::Integer) { u.i = i; }
3713
- FmtArg(unsigned int i) : type(FmtType::Unsigned) { u.u = i; }
3714
- FmtArg(long i) : type(FmtType::Integer) { u.i = i; }
3715
- FmtArg(unsigned long i) : type(FmtType::Unsigned) { u.u = i; }
3716
- FmtArg(long long i) : type(FmtType::Integer) { u.i = i; }
3717
- FmtArg(unsigned long long i) : type(FmtType::Unsigned) { u.u = i; }
3718
- FmtArg(float f) : type(FmtType::Float) { u.f = { f, 0, INT_MAX }; }
3719
- FmtArg(double d) : type(FmtType::Double) { u.d = { d, 0, INT_MAX }; }
3720
- FmtArg(const void *ptr) : type(FmtType::BigHex) { u.u = (uint64_t)ptr; }
3721
- FmtArg(const LocalDate &date) : type(FmtType::Date) { u.date = date; }
3722
-
3723
- FmtArg &Repeat(int new_repeat) { repeat = new_repeat; return *this; }
3724
- FmtArg &Pad(int len, char c = ' ') { pad_char = c; pad_len = len; return *this; }
3725
- FmtArg &Pad0(int len) { return Pad(len, '0'); }
3762
+ FmtArg(const FmtArg &other) = default;
3763
+ FmtArg(std::nullptr_t) : FmtArg(FmtType::Str) { u.str = "(null)"; }
3764
+ FmtArg(const char *str) : FmtArg(FmtType::Str) { u.str = str ? str : "(null)"; }
3765
+ FmtArg(Span<const char> str) : FmtArg(FmtType::Str) { u.str = str; }
3766
+ FmtArg(char c) : FmtArg(FmtType::Char) { u.ch = c; }
3767
+ FmtArg(const FmtCustom &custom) : FmtArg(FmtType::Custom) { u.custom = custom; }
3768
+ FmtArg(bool b) : FmtArg(FmtType::Bool) { u.b = b; }
3769
+ FmtArg(unsigned char i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3770
+ FmtArg(short i) : FmtArg(FmtType::Integer) { u.i = i; }
3771
+ FmtArg(unsigned short i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3772
+ FmtArg(int i) : FmtArg(FmtType::Integer) { u.i = i; }
3773
+ FmtArg(unsigned int i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3774
+ FmtArg(long i) : FmtArg(FmtType::Integer) { u.i = i; }
3775
+ FmtArg(unsigned long i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3776
+ FmtArg(long long i) : FmtArg(FmtType::Integer) { u.i = i; }
3777
+ FmtArg(unsigned long long i) : FmtArg(FmtType::Unsigned) { u.u = i; }
3778
+ FmtArg(float f) : FmtArg(FmtType::Float) { u.f = { f, 0, INT_MAX }; }
3779
+ FmtArg(double d) : FmtArg(FmtType::Double) { u.d = { d, 0, INT_MAX }; }
3780
+ FmtArg(const void *ptr) : FmtArg(FmtType::BigHex) { u.u = (uint64_t)ptr; }
3781
+ FmtArg(const LocalDate &date) : FmtArg(FmtType::Date) { u.date = date; }
3782
+
3783
+ protected:
3784
+ FmtArg(FmtType type) : type(type) {}
3785
+ };
3786
+
3787
+ class FmtSafe: public FmtArg {
3788
+ public:
3789
+ FmtSafe() = default;
3790
+ FmtSafe(FmtArg arg) : FmtArg(arg) {}
3791
+ FmtSafe(std::nullptr_t) : FmtArg(FmtType::Str) { u.str = "(null)"; }
3792
+ FmtSafe(const char *str) : FmtArg(FmtType::SafeStr) { u.str = str ? str : "(null)"; } // safe
3793
+ FmtSafe(Span<const char> str) : FmtArg(FmtType::SafeStr) { u.str = str; } // safe
3794
+ FmtSafe(char c) : FmtArg(FmtType::SafeChar) { u.ch = c; } // safe
3795
+ FmtSafe(const FmtCustom &custom) : FmtArg(custom) {}
3796
+ FmtSafe(bool b) : FmtArg(b) {}
3797
+ FmtSafe(unsigned char i) : FmtArg(i) {}
3798
+ FmtSafe(short i) : FmtArg(i) {}
3799
+ FmtSafe(unsigned short i) : FmtArg(i) {}
3800
+ FmtSafe(int i) : FmtArg(i) {}
3801
+ FmtSafe(unsigned int i) : FmtArg(i) {}
3802
+ FmtSafe(long i) : FmtArg(i) {}
3803
+ FmtSafe(unsigned long i) : FmtArg(i) {}
3804
+ FmtSafe(long long i) : FmtArg(i) {}
3805
+ FmtSafe(unsigned long long i) : FmtArg(i) {}
3806
+ FmtSafe(float f) : FmtArg(f) {}
3807
+ FmtSafe(double d) : FmtArg(d) {}
3808
+ FmtSafe(const void *ptr) : FmtArg(ptr) {}
3809
+ FmtSafe(const LocalDate &date) : FmtArg(date) {}
3726
3810
  };
3727
3811
 
3728
- static inline FmtArg FmtBin(uint64_t u)
3812
+ static inline FmtArg FmtInt(long long i, int pad = 0, char padding = '0')
3813
+ {
3814
+ FmtArg arg;
3815
+ arg.type = FmtType::Integer;
3816
+ arg.u.i = i;
3817
+ arg.pad = pad;
3818
+ arg.padding = padding;
3819
+ return arg;
3820
+ }
3821
+ static inline FmtArg FmtInt(unsigned long long u, int pad = 0, char padding = '0')
3822
+ {
3823
+ FmtArg arg;
3824
+ arg.type = FmtType::Unsigned;
3825
+ arg.u.u = u;
3826
+ arg.pad = pad;
3827
+ arg.padding = padding;
3828
+ return arg;
3829
+ }
3830
+ static inline FmtArg FmtInt(unsigned char u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3831
+ static inline FmtArg FmtInt(short i, int pad = 0, char padding = '0') { return FmtInt((long long)i, pad, padding); }
3832
+ static inline FmtArg FmtInt(unsigned short u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3833
+ static inline FmtArg FmtInt(int i, int pad = 0, char padding = '0') { return FmtInt((long long)i, pad, padding); }
3834
+ static inline FmtArg FmtInt(unsigned int u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3835
+ static inline FmtArg FmtInt(long i, int pad = 0, char padding = '0') { return FmtInt((long long)i, pad, padding); }
3836
+ static inline FmtArg FmtInt(unsigned long u, int pad = 0, char padding = '0') { return FmtInt((unsigned long long)u, pad, padding); }
3837
+
3838
+ static inline FmtArg FmtBin(uint64_t u, int pad = 0, char padding = '0')
3729
3839
  {
3730
3840
  FmtArg arg;
3731
3841
  arg.type = FmtType::Binary;
3732
3842
  arg.u.u = u;
3843
+ arg.pad = pad;
3844
+ arg.padding = padding;
3733
3845
  return arg;
3734
3846
  }
3735
- static inline FmtArg FmtOctal(uint64_t u)
3847
+ static inline FmtArg FmtOctal(uint64_t u, int pad = 0, char padding = '0')
3736
3848
  {
3737
3849
  FmtArg arg;
3738
3850
  arg.type = FmtType::Octal;
3739
3851
  arg.u.u = u;
3852
+ arg.pad = pad;
3853
+ arg.padding = padding;
3740
3854
  return arg;
3741
3855
  }
3742
- static inline FmtArg FmtHex(uint64_t u, FmtType type = FmtType::BigHex)
3856
+ static inline FmtArg FmtHex(uint64_t u, int pad = 0, char padding = '0')
3743
3857
  {
3744
- K_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
3745
-
3746
3858
  FmtArg arg;
3747
- arg.type = type;
3859
+ arg.type = FmtType::BigHex;
3748
3860
  arg.u.u = u;
3861
+ arg.pad = pad;
3862
+ arg.padding = padding;
3863
+ return arg;
3864
+ }
3865
+ static inline FmtArg FmtHexSmall(uint64_t u, int pad = 0, char padding = '0')
3866
+ {
3867
+ FmtArg arg;
3868
+ arg.type = FmtType::SmallHex;
3869
+ arg.u.u = u;
3870
+ arg.pad = pad;
3871
+ arg.padding = padding;
3749
3872
  return arg;
3750
3873
  }
3751
3874
 
@@ -3806,61 +3929,76 @@ static inline FmtArg FmtTimeNice(TimeSpec spec, bool ms = false)
3806
3929
  return arg;
3807
3930
  }
3808
3931
 
3809
- static inline FmtArg FmtRandom(Size len, const char *chars = nullptr)
3932
+ static inline FmtArg FmtList(Span<const char *const> names, const char *sep = ", ")
3810
3933
  {
3811
- K_ASSERT(len < 256);
3812
- len = std::min(len, (Size)256);
3813
-
3814
3934
  FmtArg arg;
3815
- arg.type = FmtType::Random;
3816
- arg.u.random.len = len;
3817
- arg.u.random.chars = chars;
3935
+ arg.type = FmtType::List;
3936
+ arg.u.list.u.names = names;
3937
+ arg.u.list.separator = sep;
3818
3938
  return arg;
3819
3939
  }
3820
-
3821
3940
  static inline FmtArg FmtFlags(uint64_t flags, Span<const char *const> names, const char *sep = ", ")
3822
3941
  {
3823
3942
  FmtArg arg;
3824
3943
  arg.type = FmtType::FlagNames;
3825
- arg.u.flags.flags = flags & ((1ull << names.len) - 1);
3826
- arg.u.flags.u.names = names;
3827
- arg.u.flags.separator = sep;
3944
+ arg.u.list.flags = flags & ((1ull << names.len) - 1);
3945
+ arg.u.list.u.names = names;
3946
+ arg.u.list.separator = sep;
3828
3947
  return arg;
3829
3948
  }
3830
-
3831
3949
  static inline FmtArg FmtFlags(uint64_t flags, Span<const struct OptionDesc> options, const char *sep = ", ")
3832
3950
  {
3833
3951
  FmtArg arg;
3834
3952
  arg.type = FmtType::FlagOptions;
3835
- arg.u.flags.flags = flags & ((1ull << options.len) - 1);
3836
- arg.u.flags.u.options = options;
3837
- arg.u.flags.separator = sep;
3953
+ arg.u.list.flags = flags & ((1ull << options.len) - 1);
3954
+ arg.u.list.u.options = options;
3955
+ arg.u.list.separator = sep;
3838
3956
  return arg;
3839
3957
  }
3840
3958
 
3841
- template <typename T>
3842
- FmtArg FmtSpan(Span<T> arr, FmtType type, const char *sep = ", ")
3959
+ static inline FmtArg FmtPad(Span<const char> str, int pad, char padding = ' ')
3843
3960
  {
3844
3961
  FmtArg arg;
3845
- arg.type = FmtType::Span;
3846
- arg.u.span.type = type;
3847
- arg.u.span.type_len = K_SIZE(T);
3848
- arg.u.span.ptr = (const void *)arr.ptr;
3849
- arg.u.span.len = arr.len;
3850
- arg.u.span.separator = sep;
3962
+ arg.type = FmtType::PadStr;
3963
+ arg.u.str = str;
3964
+ arg.pad = pad;
3965
+ arg.padding = padding;
3966
+ return arg;
3967
+ }
3968
+ static inline FmtArg FmtRepeat(const char *str, int count)
3969
+ {
3970
+ FmtArg arg;
3971
+ arg.type = FmtType::RepeatStr;
3972
+ arg.u.repeat.str = str;
3973
+ arg.u.repeat.count = count;
3974
+ return arg;
3975
+ }
3976
+
3977
+ static inline FmtArg FmtHex(Span<const uint8_t> buf)
3978
+ {
3979
+ FmtArg arg;
3980
+ arg.type = FmtType::BigBytes;
3981
+ arg.u.hex = buf;
3982
+ return arg;
3983
+ }
3984
+ static inline FmtArg FmtHexSmall(Span<const uint8_t> buf)
3985
+ {
3986
+ FmtArg arg;
3987
+ arg.type = FmtType::SmallBytes;
3988
+ arg.u.hex = buf;
3851
3989
  return arg;
3852
3990
  }
3853
- template <typename T>
3854
- FmtArg FmtSpan(Span<T> arr, const char *sep = ", ") { return FmtSpan(arr, FmtArg(T()).type, sep); }
3855
- template <typename T, Size N>
3856
- FmtArg FmtSpan(T (&arr)[N], FmtType type, const char *sep = ", ") { return FmtSpan(MakeSpan(arr), type, sep); }
3857
- template <typename T, Size N>
3858
- FmtArg FmtSpan(T (&arr)[N], const char *sep = ", ") { return FmtSpan(MakeSpan(arr), sep); }
3859
3991
 
3860
- static inline FmtArg FmtHex(Span<const uint8_t> buf, FmtType type = FmtType::BigHex)
3992
+ static inline FmtArg FmtRandom(Size len, const char *chars = nullptr)
3861
3993
  {
3862
- K_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
3863
- return FmtSpan(buf, type, "").Pad0(-2);
3994
+ K_ASSERT(len < 256);
3995
+ len = std::min(len, (Size)256);
3996
+
3997
+ FmtArg arg;
3998
+ arg.type = FmtType::Random;
3999
+ arg.u.random.len = len;
4000
+ arg.u.random.chars = chars;
4001
+ return arg;
3864
4002
  }
3865
4003
 
3866
4004
  class FmtUpperAscii {
@@ -3883,23 +4021,34 @@ public:
3883
4021
  operator FmtArg() const { return FmtCustom(*this); }
3884
4022
  };
3885
4023
 
3886
- class FmtEscape {
4024
+ class FmtUrlSafe {
3887
4025
  Span<const char> str;
4026
+ const char *passthrough;
3888
4027
 
3889
4028
  public:
3890
- FmtEscape(Span<const char> str) : str(str) {}
4029
+ FmtUrlSafe(Span<const char> str, const char *passthrough)
4030
+ : str(str), passthrough(passthrough) {}
3891
4031
 
3892
4032
  void Format(FunctionRef<void(Span<const char>)> append) const;
3893
4033
  operator FmtArg() const { return FmtCustom(*this); }
3894
4034
  };
3895
4035
 
3896
- class FmtUrlSafe {
4036
+ class FmtHtmlSafe {
3897
4037
  Span<const char> str;
3898
- const char *passthrough;
3899
4038
 
3900
4039
  public:
3901
- FmtUrlSafe(Span<const char> str, const char *passthrough)
3902
- : str(str), passthrough(passthrough) {}
4040
+ FmtHtmlSafe(Span<const char> str) : str(str) {}
4041
+
4042
+ void Format(FunctionRef<void(Span<const char>)> append) const;
4043
+ operator FmtArg() const { return FmtCustom(*this); }
4044
+ };
4045
+
4046
+ class FmtEscape {
4047
+ Span<const char> str;
4048
+ char quote;
4049
+
4050
+ public:
4051
+ FmtEscape(Span<const char> str, char quote) : str(str), quote(quote) {}
3903
4052
 
3904
4053
  void Format(FunctionRef<void(Span<const char>)> append) const;
3905
4054
  operator FmtArg() const { return FmtCustom(*this); }
@@ -4004,7 +4153,7 @@ static inline void Log(LogLevel level, const char *ctx, const char *fmt)
4004
4153
  template <typename... Args>
4005
4154
  static inline void Log(LogLevel level, const char *ctx, const char *fmt, Args... args)
4006
4155
  {
4007
- const FmtArg fmt_args[] = { FmtArg(args)... };
4156
+ const FmtArg fmt_args[] = { FmtSafe(args)... };
4008
4157
  LogFmt(level, ctx, fmt, fmt_args);
4009
4158
  }
4010
4159
 
@@ -4215,11 +4364,11 @@ static const char *const CompressionTypeExtensions[] = {
4215
4364
  Span<const char> GetPathDirectory(Span<const char> filename);
4216
4365
  Span<const char> GetPathExtension(Span<const char> filename,
4217
4366
  CompressionType *out_compression_type = nullptr);
4218
- CompressionType GetPathCompression(Span<const char> filename);
4219
4367
 
4220
4368
  enum class NormalizeFlag {
4221
4369
  EndWithSeparator = 1 << 0,
4222
- ForceSlash = 1 << 1
4370
+ ForceSlash = 1 << 1,
4371
+ NoExpansion = 1 << 2
4223
4372
  };
4224
4373
 
4225
4374
  Span<char> NormalizePath(Span<const char> path, Span<const char> root_directory, unsigned int flags, Allocator *alloc);
@@ -4233,6 +4382,7 @@ static inline Span<char> NormalizePath(Span<const char> path, Allocator *alloc)
4233
4382
  bool PathIsAbsolute(const char *path);
4234
4383
  bool PathIsAbsolute(Span<const char> path);
4235
4384
  bool PathContainsDotDot(const char *path);
4385
+ bool PathContainsDotDot(Span<const char> path);
4236
4386
 
4237
4387
  enum class StatFlag {
4238
4388
  SilentMissing = 1 << 0,
@@ -4305,7 +4455,20 @@ static inline RenameResult RenameFile(const char *src_filename, const char *dest
4305
4455
  { return RenameFile(src_filename, dest_filename, 0, flags); }
4306
4456
 
4307
4457
  bool ResizeFile(int fd, const char *filename, int64_t len);
4308
- bool SetFileMetaData(int fd, const char *filename, int64_t mtime, int64_t ctime, uint32_t mode);
4458
+
4459
+ #if !defined(_WIN32)
4460
+ bool SetFileMode(int fd, const char *filename, uint32_t mode);
4461
+ static inline bool SetFileMode(const char *filename, uint32_t mode)
4462
+ { return SetFileMode(-1, filename, mode); }
4463
+
4464
+ bool SetFileOwner(int fd, const char *filename, uint32_t uid, uint32_t gid);
4465
+ static inline bool SetFileOwner(const char *filename, uint32_t uid, uint32_t gid)
4466
+ { return SetFileOwner(-1, filename, uid, gid); }
4467
+ #endif
4468
+
4469
+ bool SetFileTimes(int fd, const char *filename, int64_t mtime, int64_t ctime);
4470
+ static inline bool SetFileTimes(const char *filename, int64_t mtime, int64_t ctime)
4471
+ { return SetFileTimes(-1, filename, mtime, ctime); }
4309
4472
 
4310
4473
  struct VolumeInfo {
4311
4474
  int64_t total;
@@ -4430,7 +4593,7 @@ void CloseHandleSafe(void **handle_ptr); // HANDLE
4430
4593
  #else
4431
4594
  void SetSignalHandler(int signal, void (*func)(int), struct sigaction *prev = nullptr);
4432
4595
 
4433
- bool CreatePipe(int pfd[2]);
4596
+ bool CreatePipe(bool block, int out_pfd[2]);
4434
4597
  void CloseDescriptorSafe(int *fd_ptr);
4435
4598
  #endif
4436
4599
 
@@ -4454,7 +4617,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4454
4617
  HeapArray<uint8_t> *out_buf, int *out_code);
4455
4618
 
4456
4619
  // Simple variants
4457
- static inline bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,int *out_code)
4620
+ static inline bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info, int *out_code)
4458
4621
  { return ExecuteCommandLine(cmd_line, info, {}, {}, out_code); }
4459
4622
  static inline bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
4460
4623
  Span<const uint8_t> in_buf,
@@ -4499,35 +4662,29 @@ enum class WaitResult {
4499
4662
  Timeout,
4500
4663
  Interrupt,
4501
4664
  Message,
4502
- Exit,
4503
- Error
4665
+ Exit
4504
4666
  };
4505
4667
 
4506
- #if defined(_WIN32)
4507
- typedef void * WaitHandle; // HANDLE
4508
- #else
4509
- typedef int WaitHandle;
4510
- #endif
4511
-
4512
4668
  struct WaitSource {
4513
4669
  #if defined(_WIN32)
4514
4670
  // Special-cased on Windows: set to NULL to wait for the Win32 message pump too
4515
4671
  void *handle; // HANDLE
4672
+ int timeout;
4516
4673
  #else
4517
4674
  int fd;
4518
- int events;
4519
- #endif
4520
-
4521
4675
  int timeout;
4676
+ int events = 0;
4677
+ #endif
4522
4678
  };
4523
4679
 
4524
4680
  // After WaitEvents() has been called once (even with timeout 0), a few signals (such as SIGINT, SIGHUP)
4525
4681
  // and their Windows equivalent will be permanently ignored.
4526
- // Beware, on Unix platforms, this may not work correctly if not called from the main thread.
4682
+ // Only the main thread (running main) will get WaitResult::Message events (and SIGUSR1).
4527
4683
  WaitResult WaitEvents(Span<const WaitSource> sources, int64_t timeout, uint64_t *out_ready = nullptr);
4528
4684
  WaitResult WaitEvents(int64_t timeout);
4529
4685
 
4530
- void InterruptWait();
4686
+ void PostWaitMessage();
4687
+ void PostTerminate();
4531
4688
 
4532
4689
  #endif
4533
4690
 
@@ -4833,12 +4990,10 @@ bool InitWinsock();
4833
4990
 
4834
4991
  int CreateSocket(SocketType type, int flags);
4835
4992
 
4836
- bool BindIPSocket(int sock, SocketType type, int port);
4993
+ bool BindIPSocket(int sock, SocketType type, const char *addr, int port);
4837
4994
  bool BindUnixSocket(int sock, const char *path);
4838
-
4839
- int OpenIPSocket(SocketType type, int port, int flags);
4840
- int OpenUnixSocket(const char *path, int flags);
4841
- int ConnectToUnixSocket(const char *path, int flags);
4995
+ bool ConnectIPSocket(int sock, const char *addr, int port);
4996
+ bool ConnectUnixSocket(int sock, const char *path);
4842
4997
 
4843
4998
  // Only for sockets on Windows
4844
4999
  void SetDescriptorNonBlock(int fd, bool enable);
@@ -4898,10 +5053,6 @@ enum class CompressionSpeed {
4898
5053
  class StreamDecoder;
4899
5054
  class StreamEncoder;
4900
5055
 
4901
- enum class StreamReaderFlag {
4902
- LazyFill = 1 << 0
4903
- };
4904
-
4905
5056
  class StreamReader {
4906
5057
  K_DELETE_COPY(StreamReader)
4907
5058
 
@@ -4912,7 +5063,6 @@ class StreamReader {
4912
5063
  };
4913
5064
 
4914
5065
  const char *filename = nullptr;
4915
- bool lazy = false;
4916
5066
  bool error = true;
4917
5067
 
4918
5068
  int64_t read_total = 0;
@@ -4952,30 +5102,24 @@ class StreamReader {
4952
5102
 
4953
5103
  public:
4954
5104
  StreamReader() { Close(true); }
4955
- StreamReader(Span<const uint8_t> buf, const char *filename, unsigned int flags = 0,
4956
- CompressionType compression_type = CompressionType::None)
4957
- : StreamReader() { Open(buf, filename, flags, compression_type); }
4958
- StreamReader(int fd, const char *filename, unsigned int flags = 0,
5105
+ StreamReader(Span<const uint8_t> buf, const char *filename, CompressionType compression_type = CompressionType::None)
5106
+ : StreamReader() { Open(buf, filename, compression_type); }
5107
+ StreamReader(int fd, const char *filename, CompressionType compression_type = CompressionType::None)
5108
+ : StreamReader() { Open(fd, filename, compression_type); }
5109
+ StreamReader(const char *filename, CompressionType compression_type = CompressionType::None)
5110
+ : StreamReader() { Open(filename, compression_type); }
5111
+ StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename,
4959
5112
  CompressionType compression_type = CompressionType::None)
4960
- : StreamReader() { Open(fd, filename, flags, compression_type); }
4961
- StreamReader(const char *filename, unsigned int flags = 0,
4962
- CompressionType compression_type = CompressionType::None)
4963
- : StreamReader() { Open(filename, flags, compression_type); }
4964
- StreamReader(const std::function<Size(Span<uint8_t>)> &func, const char *filename, unsigned int flags = 0,
4965
- CompressionType compression_type = CompressionType::None)
4966
- : StreamReader() { Open(func, filename, flags, compression_type); }
5113
+ : StreamReader() { Open(func, filename, compression_type); }
4967
5114
  ~StreamReader() { Close(true); }
4968
5115
 
4969
5116
  // Call before Open. Takes ownership and deletes the decoder at the end.
4970
5117
  void SetDecoder(StreamDecoder *decoder);
4971
5118
 
4972
- bool Open(Span<const uint8_t> buf, const char *filename, unsigned int flags = 0,
4973
- CompressionType compression_type = CompressionType::None);
4974
- bool Open(int fd, const char *filename, unsigned int flags = 0,
4975
- CompressionType compression_type = CompressionType::None);
4976
- OpenResult Open(const char *filename, unsigned int flags = 0,
4977
- CompressionType compression_type = CompressionType::None);
4978
- bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename, unsigned int flags = 0,
5119
+ bool Open(Span<const uint8_t> buf, const char *filename, CompressionType compression_type = CompressionType::None);
5120
+ bool Open(int fd, const char *filename, CompressionType compression_type = CompressionType::None);
5121
+ OpenResult Open(const char *filename, CompressionType compression_type = CompressionType::None);
5122
+ bool Open(const std::function<Size(Span<uint8_t>)> &func, const char *filename,
4979
5123
  CompressionType compression_type = CompressionType::None);
4980
5124
  bool Close() { return Close(false); }
4981
5125
 
@@ -4995,7 +5139,11 @@ public:
4995
5139
  // Thread safe methods
4996
5140
  Size Read(Span<uint8_t> out_buf);
4997
5141
  Size Read(Span<char> out_buf) { return Read(out_buf.As<uint8_t>()); }
4998
- Size Read(Size buf_len, void *out_buf) { return Read(MakeSpan((uint8_t *)out_buf, buf_len)); }
5142
+
5143
+ // Thread safe methods
5144
+ Size ReadFill(Span<uint8_t> out_buf);
5145
+ Size ReadFill(Span<char> out_buf) { return ReadFill(out_buf.As<uint8_t>()); }
5146
+ Size ReadFill(Size buf_len, void *out_buf) { return ReadFill(MakeSpan((uint8_t *)out_buf, buf_len)); }
4999
5147
 
5000
5148
  Size ReadAll(Size max_len, HeapArray<uint8_t> *out_buf);
5001
5149
  Size ReadAll(Size max_len, HeapArray<char> *out_buf)
@@ -5017,12 +5165,12 @@ private:
5017
5165
  static inline Size ReadFile(const char *filename, Span<uint8_t> out_buf)
5018
5166
  {
5019
5167
  StreamReader st(filename);
5020
- return st.Read(out_buf);
5168
+ return st.ReadFill(out_buf);
5021
5169
  }
5022
5170
  static inline Size ReadFile(const char *filename, Span<char> out_buf)
5023
5171
  {
5024
5172
  StreamReader st(filename);
5025
- return st.Read(out_buf);
5173
+ return st.ReadFill(out_buf);
5026
5174
  }
5027
5175
  static inline Size ReadFile(const char *filename, Size max_len, HeapArray<uint8_t> *out_buf)
5028
5176
  {
@@ -5626,10 +5774,23 @@ bool OptionToFlagI(Span<const OptionDesc> options, Span<const char> str, T *out_
5626
5774
  // ------------------------------------------------------------------------
5627
5775
 
5628
5776
  struct PromptChoice {
5629
- char c;
5630
5777
  const char *str;
5778
+ char c;
5779
+ };
5780
+
5781
+ enum class CompleteResult {
5782
+ Success,
5783
+ TooMany,
5784
+ Error
5631
5785
  };
5632
5786
 
5787
+ struct CompleteChoice {
5788
+ const char *name;
5789
+ const char *value;
5790
+ };
5791
+
5792
+ typedef CompleteResult CompleteFunc(Span<const char> value, Allocator *alloc, HeapArray<CompleteChoice> *out_choices);
5793
+
5633
5794
  class ConsolePrompter {
5634
5795
  int prompt_columns = 0;
5635
5796
 
@@ -5651,6 +5812,7 @@ class ConsolePrompter {
5651
5812
  public:
5652
5813
  const char *prompt = ">>>";
5653
5814
  const char *mask = nullptr;
5815
+ std::function<CompleteFunc> complete = {};
5654
5816
 
5655
5817
  HeapArray<char> str;
5656
5818
 
@@ -5695,6 +5857,13 @@ static inline const char *Prompt(const char *prompt, Allocator *alloc)
5695
5857
  Size PromptEnum(const char *prompt, Span<const PromptChoice> choices, Size value = 0);
5696
5858
  Size PromptEnum(const char *prompt, Span<const char *const> strings, Size value = 0);
5697
5859
 
5860
+ // Returns -1 if cancelled, otherwise it's 1 for Yes and or 0 for No
5861
+ int PromptYN(const char *prompt);
5862
+
5863
+ const char *PromptPath(const char *prompt, const char *default_path, Span<const char> root_directory, Allocator *alloc);
5864
+ static inline const char *PromptPath(const char *prompt, Allocator *alloc)
5865
+ { return PromptPath(prompt, nullptr, GetWorkingDirectory(), alloc); }
5866
+
5698
5867
  // ------------------------------------------------------------------------
5699
5868
  // Mime types
5700
5869
  // ------------------------------------------------------------------------