summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2026-02-13 23:59:41 +0800
committerSaikari <[email protected]>2026-02-20 16:31:35 +0300
commitcc3ccaeefb01d2e4650ff850d74a04bfa2b62a63 (patch)
tree4eebb851ebc402f334cd3f547e235dfc8c7500a1
parentb065878db47435b7ebfa9f29020c927b4eff8f7e (diff)
add haiku ci
-rw-r--r--.github/workflows/haiku.yml81
m---------core/src/tbox/tbox0
-rw-r--r--core/src/xmake/string/lower.c162
3 files changed, 242 insertions, 1 deletions
diff --git a/.github/workflows/haiku.yml b/.github/workflows/haiku.yml
new file mode 100644
index 000000000..f277d263f
--- /dev/null
+++ b/.github/workflows/haiku.yml
@@ -0,0 +1,81 @@
+name: Haiku
+
+on:
+ pull_request:
+ push:
+ release:
+ types: [published]
+
+jobs:
+ check:
+ runs-on: ubuntu-latest
+ outputs:
+ should-run: ${{ steps.check.outputs.should-run }}
+ steps:
+ - name: Random execution check
+ id: check
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const fs = require('fs');
+ const outputFile = process.env.GITHUB_OUTPUT;
+
+ if (context.eventName === 'release') {
+ fs.appendFileSync(outputFile, `should-run=true\n`);
+ core.info('Release event detected. Will run tests.');
+ return;
+ }
+
+ const probability = parseFloat(process.env.RUN_PROBABILITY || '0.2');
+ const timeSeed = Math.floor(Date.now() / (1000 * 60 * 60));
+ const seed = context.sha + context.runId + timeSeed;
+ let hash = 0;
+ for (let i = 0; i < seed.length; i++) {
+ const char = seed.charCodeAt(i);
+ hash = ((hash << 5) - hash) + char;
+ hash = hash | 0;
+ }
+ const random = Math.abs(hash) / 2147483647;
+ const shouldRun = random < probability;
+
+ fs.appendFileSync(outputFile, `should-run=${shouldRun}\n`);
+ if (shouldRun) {
+ core.info(`Random check passed (${(random * 100).toFixed(2)}% < ${(probability * 100).toFixed(0)}%). Will run tests.`);
+ } else {
+ core.info(`Random check failed (${(random * 100).toFixed(2)}% >= ${(probability * 100).toFixed(0)}%). Skipping.`);
+ }
+ env:
+ RUN_PROBABILITY: ${{ vars.HAIKU_RUN_PROBABILITY || '0.2' }}
+
+ build:
+ #needs: check
+ #if: needs.check.outputs.should-run == 'true'
+ runs-on: ubuntu-latest
+
+ concurrency:
+ group: Haiku-${{ github.event.repository.owner.login }}-${{ github.event.repository.name }}
+ cancel-in-progress: false
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ submodules: true
+
+ - name: Tests
+ uses: vmactions/haiku-vm@v1
+ with:
+ usesh: true
+ mem: 4096
+ copyback: false
+ prepare: |
+ pkgman install -y git curl unzip make bash perl
+ run: |
+ pwd
+ ./configure --prefix=`pwd`/dist
+ make -j2
+ make install
+ ls -l ./dist/
+ export XMAKE_ROOT=y
+ export PATH=`pwd`/dist/bin:$PATH
+ xrepo --version
+ xmake l os.meminfo
+ xmake l string.lower "Test 源文件🎆 Message"
diff --git a/core/src/tbox/tbox b/core/src/tbox/tbox
-Subproject ef851bcb6589b6092f5bd3fca4625631237f9bd
+Subproject 75c90b4c4313f84f8247867c99721882e390f40
diff --git a/core/src/xmake/string/lower.c b/core/src/xmake/string/lower.c
index 71f8408dc..07ae4bff4 100644
--- a/core/src/xmake/string/lower.c
+++ b/core/src/xmake/string/lower.c
@@ -23,6 +23,166 @@
* includes
*/
#include "prefix.h"
+# include <wctype.h>
+
+static __tb_inline__ tb_bool_t tb_unicode_tolower_try(tb_uint32_t ch, tb_uint32_t* out)
+{
+ // builtin, locale-independent case mapping for some common unicode ranges:
+ // - Basic Latin (ASCII)
+ // - Latin-1 Supplement (partial)
+ // - Latin Extended-A (partial)
+ // - Greek (partial)
+ // - Cyrillic (partial)
+ if (sizeof(tb_wchar_t) == 2 && ch >= 0xd800 && ch <= 0xdfff) return tb_false;
+
+ // Basic Latin (ASCII)
+ if (ch <= 0x7f)
+ {
+ tb_trace_i("basic: %x", ch);
+ *out = tb_tolower(ch);
+ return tb_true;
+ }
+
+ // Latin-1 Supplement: U+00C0..U+00D6, U+00D8..U+00DE
+ if ((ch >= 0x00c0 && ch <= 0x00d6) || (ch >= 0x00d8 && ch <= 0x00de)) { *out = ch + 0x20; return tb_true; }
+ // Latin-1 Supplement: U+00E0..U+00F6, U+00F8..U+00FE
+ if ((ch >= 0x00e0 && ch <= 0x00f6) || (ch >= 0x00f8 && ch <= 0x00fe)) { *out = ch; return tb_true; }
+
+ // Latin-1 Supplement: U+0178 <-> U+00FF
+ if (ch == 0x0178) { *out = 0x00ff; return tb_true; }
+ if (ch == 0x00ff) { *out = ch; return tb_true; }
+
+ // Latin Extended Additional: U+1E9E <-> U+00DF
+ if (ch == 0x1e9e) { *out = 0x00df; return tb_true; }
+ if (ch == 0x00df) { *out = ch; return tb_true; }
+
+ // Latin Extended-A: many letters have alternating upper/lower code points
+ if (ch >= 0x0100 && ch <= 0x012f) { *out = (ch & 0x1) ? ch : (ch + 1); return tb_true; }
+ if (ch >= 0x0132 && ch <= 0x0137) { *out = (ch & 0x1) ? ch : (ch + 1); return tb_true; }
+ if (ch >= 0x0139 && ch <= 0x0148) { *out = (ch & 0x1) ? (ch + 1) : ch; return tb_true; }
+ if (ch >= 0x014a && ch <= 0x0177) { *out = (ch & 0x1) ? ch : (ch + 1); return tb_true; }
+ if (ch >= 0x0179 && ch <= 0x017e) { *out = (ch & 0x1) ? (ch + 1) : ch; return tb_true; }
+ // Latin Extended-A: long s (already lowercase)
+ if (ch == 0x017f) { *out = ch; return tb_true; }
+
+ // Greek and Coptic (partial): U+0391..U+03A1, U+03A3..U+03AB
+ if ((ch >= 0x0391 && ch <= 0x03a1) || (ch >= 0x03a3 && ch <= 0x03ab)) { *out = ch + 0x20; return tb_true; }
+ // Greek and Coptic (partial): U+03B1..U+03C1, U+03C3..U+03CB, and U+03C2
+ if ((ch >= 0x03b1 && ch <= 0x03c1) || (ch >= 0x03c3 && ch <= 0x03cb) || ch == 0x03c2) { *out = ch; return tb_true; }
+
+ // Cyrillic (partial): U+0401/U+0451 and U+0410..U+042F
+ if (ch == 0x0401) { *out = 0x0451; return tb_true; }
+ if (ch == 0x0451) { *out = ch; return tb_true; }
+ if (ch >= 0x0402 && ch <= 0x040f) { *out = ch + 0x50; return tb_true; }
+ if (ch >= 0x0452 && ch <= 0x045f) { *out = ch; return tb_true; }
+ if (ch >= 0x0410 && ch <= 0x042f) { *out = ch + 0x20; return tb_true; }
+
+ if (ch >= 0x0430 && ch <= 0x044f) {
+ *out = ch;
+ return tb_true;
+ }
+
+ return tb_false;
+}
+
+tb_wchar_t tb_towlower_test(tb_wchar_t c)
+{
+ tb_trace_i("towlower: %x, wchar: %d", (tb_uint32_t)c, sizeof(tb_wchar_t));
+ tb_uint32_t ch = tb_bits_wchar_to_u32_le(c);
+ tb_uint32_t out;
+ if (__tb_likely__(tb_unicode_tolower_try(ch, &out))) {
+ tb_trace_i("towlower: out: %x", out);
+ return tb_bits_u32_le_to_wchar(out);
+ }
+
+ tb_trace_i("towlower xxx: %x", (tb_uint32_t)c);
+ return (tb_wchar_t)towlower((tb_uint32_t)c);
+}
+
+static tb_wchar_t* tb_wcslwr_test(tb_wchar_t* s)
+{
+ // check
+ tb_assert_and_check_return_val(s, tb_null);
+
+ // set local locale
+ tb_setlocale();
+
+ tb_wchar_t* p = s;
+ while (*p)
+ {
+ *p = tb_towlower_test(*p);
+ p++;
+ }
+
+ // set default locale
+ tb_resetlocale();
+
+ return s;
+}
+
+static tb_size_t tb_mbstowcs_charset(tb_wchar_t* s1, tb_char_t const* s2, tb_size_t n)
+{
+ // check
+ tb_assert_and_check_return_val(s1 && s2, 0);
+
+ // init
+ tb_size_t e = (sizeof(tb_wchar_t) == 4) ? TB_CHARSET_TYPE_UTF32 : TB_CHARSET_TYPE_UTF16;
+ tb_long_t r = tb_charset_conv_cstr(TB_CHARSET_TYPE_UTF8, e | TB_CHARSET_TYPE_LE, s2,
+ (tb_byte_t*)s1, n * sizeof(tb_wchar_t));
+ if (r > 0) r /= sizeof(tb_wchar_t);
+
+ // strip
+ if (r >= 0) s1[r] = L'\0';
+
+ tb_trace_i("tb_mbstowcs_charset: %ld", r);
+ // ok?
+ return r >= 0 ? r : -1;
+}
+
+static tb_long_t tb_charset_utf8_tolower_test(tb_char_t* s, tb_size_t n)
+{
+ tb_assert_and_check_return_val(s, -1);
+
+ tb_trace_i("s: %s: %d", s, n);
+
+ // try ascii tolower first
+ tb_char_t* p = s;
+ tb_char_t* e = s + n;
+ while (p < e && *p)
+ {
+ if ((*p) & 0x80) {
+ break;
+ }
+ tb_trace_i("old: %c -> %x", *p);
+ *p = tb_tolower(*p);
+ tb_trace_i("new: %c -> %x", *p);
+ p++;
+ }
+ tb_trace_i("test: %d %d", p == e, !*p);
+
+ if (p == e || !*p) return p - s;
+
+ // convert the suffix to wchar_t
+ tb_long_t r = -1;
+ tb_size_t wn = e - p + 1;
+ tb_wchar_t wb[256];
+ tb_wchar_t* w = (wn <= 256)? wb : (tb_wchar_t*)tb_malloc(wn * sizeof(tb_wchar_t));
+ if (w)
+ {
+ tb_trace_i("tb_mbstowcs 111");
+ if (tb_mbstowcs_charset(w, p, wn) != -1)
+ {
+ tb_trace_i("tb_wcslwr_test 111");
+ tb_wcslwr_test(w);
+ r = tb_wcstombs(p, w, wn);
+ if (r != -1) r += (p - s);
+ }
+
+ tb_trace_i("tb_free 111");
+ if (w != wb) tb_free(w);
+ }
+ return r;
+}
/* //////////////////////////////////////////////////////////////////////////////////////
* implementation
@@ -58,7 +218,7 @@ tb_int_t xm_string_lower(lua_State *lua) {
buffer[size] = '\0';
// to lower
- tb_long_t real_size = tb_charset_utf8_tolower(buffer, size);
+ tb_long_t real_size = tb_charset_utf8_tolower_test(buffer, size);
// push result
if (real_size >= 0) {