#include static inline u32 find_number(str *s) { u32 i = 0; while (i < s->length && !al_isnumber(al_str_at(s, i))) { i++; } return (i == s->length) ? AL_STR_NO_POS : i; } static inline u32 find_non_number(str *s) { u32 i = 0; while (i < s->length && al_isnumber(al_str_at(s, i))) { i++; } return i; } s32 nn_numerical_compare(const void *a, const void *b) { str s1 = *(str *)a, s2 = *(str *)b; s32 ret; str sub1, sub2; bool error; s64 n1, n2; u32 nn1 = find_number(&s1); u32 nn2 = find_number(&s2); if (nn1 != nn2) { goto compare_remainder; } s1 = al_str_substr(&s1, nn1, s1.length); s2 = al_str_substr(&s2, nn2, s2.length); do { nn1 = find_non_number(&s1); nn2 = find_non_number(&s2); sub1 = al_str_substr(&s1, 0, nn1); sub2 = al_str_substr(&s2, 0, nn2); n1 = al_str_to_long(&sub1, 10, &error); al_assert(!error); n2 = al_str_to_long(&sub2, 10, &error); al_assert(!error); if (n1 > n2) return 1; else if (n1 < n2) return -1; s1 = al_str_substr(&s1, nn1, s1.length); s2 = al_str_substr(&s2, nn2, s2.length); nn1 = find_number(&s1); nn2 = find_number(&s2); if (nn1 == AL_STR_NO_POS || nn2 == AL_STR_NO_POS) { goto compare_remainder; } sub1 = al_str_substr(&s1, 0, nn1); sub2 = al_str_substr(&s2, 0, nn2); if (!al_str_eq(&sub1, &sub2)) { goto compare_remainder; } s1 = al_str_substr(&s1, nn1, s1.length); s2 = al_str_substr(&s2, nn2, s2.length); } while (1); compare_remainder: ret = al_str_cmp(&s1, &s2, 0, MIN(s1.length, s2.length)); if (ret == 0) return s1.length - s2.length; return ret; }