2016-03-21 20:42:14 +01:00
|
|
|
#include "Emu/Cell/PPUModule.h"
|
2025-10-04 15:46:36 +02:00
|
|
|
#include "cellos/sys_tty.h"
|
2025-04-08 18:46:57 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "util/cfmt.h"
|
2015-02-26 21:08:48 +01:00
|
|
|
|
2020-01-31 10:01:17 +01:00
|
|
|
LOG_CHANNEL(sysPrxForUser);
|
2015-02-26 21:08:48 +01:00
|
|
|
|
2017-03-25 22:25:28 +01:00
|
|
|
// cfmt implementation (TODO)
|
2017-05-26 07:02:28 +02:00
|
|
|
|
2018-02-20 21:24:47 +01:00
|
|
|
using qsortcmp = s32(vm::cptr<void> e1, vm::cptr<void> e2);
|
|
|
|
|
|
2017-03-25 22:25:28 +01:00
|
|
|
struct ps3_fmt_src
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-03-25 22:25:28 +01:00
|
|
|
ppu_thread* ctx;
|
|
|
|
|
u32 g_count;
|
|
|
|
|
|
2021-04-09 21:12:47 +02:00
|
|
|
static bool test(usz)
|
2017-03-25 22:25:28 +01:00
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2020-12-18 08:39:54 +01:00
|
|
|
T get(usz index) const
|
2017-03-25 22:25:28 +01:00
|
|
|
{
|
2019-12-02 22:31:34 +01:00
|
|
|
const u32 i = static_cast<u32>(index) + g_count;
|
2017-03-25 22:25:28 +01:00
|
|
|
return ppu_gpr_cast<T>(i < 8 ? ctx->gpr[3 + i] : +*ctx->get_stack_arg(i));
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-18 08:39:54 +01:00
|
|
|
void skip(usz extra)
|
2017-03-25 22:25:28 +01:00
|
|
|
{
|
2019-12-02 22:31:34 +01:00
|
|
|
g_count += static_cast<u32>(extra) + 1;
|
2017-03-25 22:25:28 +01:00
|
|
|
}
|
|
|
|
|
|
2020-12-18 08:39:54 +01:00
|
|
|
usz fmt_string(std::string& out, usz extra) const
|
2017-03-25 22:25:28 +01:00
|
|
|
{
|
2020-12-18 08:39:54 +01:00
|
|
|
const usz start = out.size();
|
2018-02-09 15:49:37 +01:00
|
|
|
out += vm::_ptr<const char>(get<u32>(extra));
|
2017-03-25 22:25:28 +01:00
|
|
|
return out.size() - start;
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2021-04-09 21:12:47 +02:00
|
|
|
static usz type(usz)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-03-25 22:25:28 +01:00
|
|
|
return 0;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
2017-05-16 13:29:07 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr usz size_char = 1;
|
2020-12-18 08:39:54 +01:00
|
|
|
static constexpr usz size_short = 2;
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr usz size_int = 4;
|
|
|
|
|
static constexpr usz size_long = 4;
|
2020-12-18 08:39:54 +01:00
|
|
|
static constexpr usz size_llong = 8;
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr usz size_size = 4;
|
|
|
|
|
static constexpr usz size_max = 8;
|
|
|
|
|
static constexpr usz size_diff = 4;
|
2017-03-25 22:25:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <>
|
2020-12-18 08:39:54 +01:00
|
|
|
f64 ps3_fmt_src::get<f64>(usz index) const
|
2017-03-25 22:25:28 +01:00
|
|
|
{
|
2019-06-01 23:12:17 +02:00
|
|
|
return std::bit_cast<f64>(get<u64>(index));
|
2017-03-25 22:25:28 +01:00
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
static std::string ps3_fmt(ppu_thread& context, vm::cptr<char> fmt,
|
|
|
|
|
u32 g_count)
|
2017-03-25 22:25:28 +01:00
|
|
|
{
|
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
|
|
cfmt_append(result, fmt.get_ptr(), ps3_fmt_src{&context, g_count});
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const std::array<s16, 129> s_ctype_table{
|
2017-09-17 10:25:27 +02:00
|
|
|
0,
|
2025-04-05 21:50:45 +02:00
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x408,
|
|
|
|
|
8,
|
|
|
|
|
8,
|
|
|
|
|
8,
|
|
|
|
|
8,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
|
|
|
|
0x20,
|
2017-09-17 10:25:27 +02:00
|
|
|
0x18,
|
2025-04-05 21:50:45 +02:00
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
4,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x41,
|
|
|
|
|
0x41,
|
|
|
|
|
0x41,
|
|
|
|
|
0x41,
|
|
|
|
|
0x41,
|
|
|
|
|
0x41,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
1,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x42,
|
|
|
|
|
0x42,
|
|
|
|
|
0x42,
|
|
|
|
|
0x42,
|
|
|
|
|
0x42,
|
|
|
|
|
0x42,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
2,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x10,
|
|
|
|
|
0x20,
|
2017-09-17 10:25:27 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
s16 __sys_look_ctype_table(s32 ch)
|
|
|
|
|
{
|
|
|
|
|
sysPrxForUser.trace("__sys_look_ctype_table(ch=%d)", ch);
|
|
|
|
|
|
2020-12-09 08:47:45 +01:00
|
|
|
ensure(ch >= -1 && ch <= 127); // "__sys_look_ctype_table"
|
2017-09-17 10:25:27 +02:00
|
|
|
|
|
|
|
|
return s_ctype_table[ch + 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_tolower(s32 ch)
|
|
|
|
|
{
|
|
|
|
|
sysPrxForUser.trace("_sys_tolower(ch=%d)", ch);
|
|
|
|
|
|
2020-12-09 08:47:45 +01:00
|
|
|
ensure(ch >= -1 && ch <= 127); // "_sys_tolower"
|
2017-09-17 10:25:27 +02:00
|
|
|
|
|
|
|
|
return s_ctype_table[ch + 1] & 1 ? ch + 0x20 : ch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_toupper(s32 ch)
|
|
|
|
|
{
|
|
|
|
|
sysPrxForUser.trace("_sys_toupper(ch=%d)", ch);
|
|
|
|
|
|
2020-12-09 08:47:45 +01:00
|
|
|
ensure(ch >= -1 && ch <= 127); // "_sys_toupper"
|
2017-09-17 10:25:27 +02:00
|
|
|
|
|
|
|
|
return s_ctype_table[ch + 1] & 2 ? ch - 0x20 : ch;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-02 04:15:49 +02:00
|
|
|
vm::ptr<void> _sys_memset(vm::ptr<void> dst, s32 value, u32 size)
|
|
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_memset(dst=*0x%x, value=%d, size=0x%x)", dst, value,
|
|
|
|
|
size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
std::memset(dst.get_ptr(), value, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm::ptr<void> _sys_memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
|
|
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_memcpy(dst=*0x%x, src=*0x%x, size=0x%x)", dst, src,
|
|
|
|
|
size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
std::memcpy(dst.get_ptr(), src.get_ptr(), size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-17 12:52:57 +02:00
|
|
|
s32 _sys_memcmp(vm::cptr<u8> buf1, vm::cptr<u8> buf2, u32 size)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_memcmp(buf1=*0x%x, buf2=*0x%x, size=%d)", buf1,
|
|
|
|
|
buf2, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 12:52:57 +02:00
|
|
|
for (u32 i = 0; i < size; i++)
|
|
|
|
|
{
|
|
|
|
|
const u8 b1 = buf1[i], b2 = buf2[i];
|
|
|
|
|
|
|
|
|
|
if (b1 < b2)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (b1 > b2)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-07-11 23:49:58 +02:00
|
|
|
vm::ptr<u8> _sys_memchr(vm::ptr<u8> buf, u8 ch, s32 size)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_memchr(buf=*0x%x, ch=0x%x, size=0x%x)", buf, ch,
|
|
|
|
|
size);
|
2017-07-11 23:49:58 +02:00
|
|
|
|
|
|
|
|
if (!buf)
|
|
|
|
|
{
|
|
|
|
|
return vm::null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (size > 0)
|
|
|
|
|
{
|
|
|
|
|
if (*buf == ch)
|
|
|
|
|
{
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf++;
|
|
|
|
|
size--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return vm::null;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2016-02-16 19:54:09 +01:00
|
|
|
vm::ptr<void> _sys_memmove(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_memmove(dst=*0x%x, src=*0x%x, size=%d)", dst, src,
|
|
|
|
|
size);
|
2016-02-16 19:54:09 +01:00
|
|
|
|
2016-08-11 01:29:59 +02:00
|
|
|
std::memmove(dst.get_ptr(), src.get_ptr(), size);
|
2016-02-16 19:54:09 +01:00
|
|
|
|
|
|
|
|
return dst;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 13:05:48 +02:00
|
|
|
u32 _sys_strlen(vm::cptr<char> str)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strlen(str=%s)", str);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 13:05:48 +02:00
|
|
|
if (!str)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0;; i++)
|
|
|
|
|
{
|
|
|
|
|
if (str[i] == '\0')
|
|
|
|
|
{
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s32 _sys_strcmp(vm::cptr<char> str1, vm::cptr<char> str2)
|
|
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.trace("_sys_strcmp(str1=%s, str2=%s)", str1, str2);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 13:14:15 +02:00
|
|
|
for (u32 i = 0;; i++)
|
|
|
|
|
{
|
|
|
|
|
const u8 ch1 = str1[i], ch2 = str2[i];
|
|
|
|
|
if (ch1 < ch2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (ch1 > ch2)
|
|
|
|
|
return 1;
|
|
|
|
|
if (ch1 == '\0')
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 13:16:15 +02:00
|
|
|
s32 _sys_strncmp(vm::cptr<char> str1, vm::cptr<char> str2, u32 max)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_strncmp(str1=%s, str2=%s, max=%d)", str1, str2,
|
|
|
|
|
max);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 13:16:15 +02:00
|
|
|
for (u32 i = 0; i < max; i++)
|
|
|
|
|
{
|
|
|
|
|
const u8 ch1 = str1[i], ch2 = str2[i];
|
|
|
|
|
if (ch1 < ch2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (ch1 > ch2)
|
|
|
|
|
return 1;
|
|
|
|
|
if (ch1 == '\0')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 13:46:57 +02:00
|
|
|
vm::ptr<char> _sys_strcat(vm::ptr<char> dst, vm::cptr<char> src)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-09-17 13:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_strcat(dst=*0x%x %s, src=%s)", dst, dst, src);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 13:46:57 +02:00
|
|
|
auto str = dst;
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 13:46:57 +02:00
|
|
|
while (*str)
|
|
|
|
|
{
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0;; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!(str[i] = src[i]))
|
|
|
|
|
{
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 14:56:17 +02:00
|
|
|
vm::cptr<char> _sys_strchr(vm::cptr<char> str, char ch)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-09-17 14:56:17 +02:00
|
|
|
sysPrxForUser.trace("_sys_strchr(str=%s, ch=%d)", str, ch);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 14:56:17 +02:00
|
|
|
for (u32 i = 0;; i++)
|
|
|
|
|
{
|
|
|
|
|
const char ch1 = str[i];
|
|
|
|
|
if (ch1 == ch)
|
|
|
|
|
return str + i;
|
|
|
|
|
if (ch1 == '\0')
|
|
|
|
|
return vm::null;
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 17:28:52 +02:00
|
|
|
vm::ptr<char> _sys_strncat(vm::ptr<char> dst, vm::cptr<char> src, u32 max)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_strncat(dst=*0x%x %s, src=%s, max=%u)", dst, dst,
|
|
|
|
|
src, max);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 17:28:52 +02:00
|
|
|
auto str = dst;
|
|
|
|
|
|
|
|
|
|
while (*str)
|
|
|
|
|
{
|
|
|
|
|
str++;
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 17:28:52 +02:00
|
|
|
for (u32 i = 0; i < max; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!(str[i] = src[i]))
|
|
|
|
|
{
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str[max] = '\0';
|
|
|
|
|
return dst;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 14:43:58 +02:00
|
|
|
vm::ptr<char> _sys_strcpy(vm::ptr<char> dst, vm::cptr<char> src)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-09-17 14:43:58 +02:00
|
|
|
sysPrxForUser.trace("_sys_strcpy(dst=*0x%x, src=%s)", dst, src);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 14:43:58 +02:00
|
|
|
for (u32 i = 0;; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!(dst[i] = src[i]))
|
|
|
|
|
{
|
|
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 15:49:33 +02:00
|
|
|
vm::ptr<char> _sys_strncpy(vm::ptr<char> dst, vm::cptr<char> src, s32 len)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_strncpy(dst=*0x%x %s, src=%s, len=%d)", dst, dst,
|
|
|
|
|
src, len);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 15:49:33 +02:00
|
|
|
if (!dst || !src)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
|
|
|
|
return vm::null;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-17 15:49:33 +02:00
|
|
|
for (s32 i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
if (!(dst[i] = src[i]))
|
|
|
|
|
{
|
|
|
|
|
for (++i; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
dst[i] = '\0';
|
|
|
|
|
}
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-09-17 15:49:33 +02:00
|
|
|
return dst;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dst;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 12:53:23 +02:00
|
|
|
s32 _sys_strncasecmp(vm::cptr<char> str1, vm::cptr<char> str2, u32 n)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.trace("_sys_strncasecmp(str1=%s, str2=%s, n=%d)", str1, str2,
|
|
|
|
|
n);
|
2018-02-09 15:49:37 +01:00
|
|
|
|
2017-05-26 07:02:28 +02:00
|
|
|
for (u32 i = 0; i < n; i++)
|
|
|
|
|
{
|
2017-09-17 10:25:27 +02:00
|
|
|
const int ch1 = _sys_tolower(str1[i]), ch2 = _sys_tolower(str2[i]);
|
2017-05-26 07:02:28 +02:00
|
|
|
if (ch1 < ch2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (ch1 > ch2)
|
|
|
|
|
return 1;
|
|
|
|
|
if (ch1 == '\0')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-17 15:03:30 +02:00
|
|
|
vm::cptr<char> _sys_strrchr(vm::cptr<char> str, char ch)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-09-17 15:03:30 +02:00
|
|
|
sysPrxForUser.trace("_sys_strrchr(str=%s, ch=%d)", str, ch);
|
2018-02-09 15:49:37 +01:00
|
|
|
|
2017-09-17 15:03:30 +02:00
|
|
|
vm::cptr<char> res = vm::null;
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0;; i++)
|
|
|
|
|
{
|
|
|
|
|
const char ch1 = str[i];
|
|
|
|
|
if (ch1 == ch)
|
|
|
|
|
res = str + i;
|
|
|
|
|
if (ch1 == '\0')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 _sys_malloc(u32 size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.warning("_sys_malloc(size=0x%x)", size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
return vm::alloc(size, vm::main);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 _sys_memalign(u32 align, u32 size)
|
|
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.warning("_sys_memalign(align=0x%x, size=0x%x)", align, size);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2018-05-07 20:57:06 +02:00
|
|
|
return vm::alloc(size, vm::main, std::max<u32>(align, 0x10000));
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 12:14:57 +02:00
|
|
|
error_code _sys_free(u32 addr)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2016-01-12 22:57:16 +01:00
|
|
|
sysPrxForUser.warning("_sys_free(addr=0x%x)", addr);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
vm::dealloc(addr, vm::main);
|
|
|
|
|
|
|
|
|
|
return CELL_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
s32 _sys_snprintf(ppu_thread& ppu, vm::ptr<char> dst, u32 count,
|
|
|
|
|
vm::cptr<char> fmt, ppu_va_args_t va_args)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=%s, ...)", dst,
|
|
|
|
|
count, fmt);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2016-03-21 20:42:14 +01:00
|
|
|
std::string result = ps3_fmt(ppu, fmt, va_args.count);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
|
|
|
|
if (!count)
|
|
|
|
|
{
|
|
|
|
|
return 0; // ???
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-12-18 08:39:54 +01:00
|
|
|
count = static_cast<u32>(std::min<usz>(count - 1, result.size()));
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2017-03-25 22:25:28 +01:00
|
|
|
std::memcpy(dst.get_ptr(), result.c_str(), count);
|
2015-08-02 04:15:49 +02:00
|
|
|
dst[count] = 0;
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
error_code _sys_printf(ppu_thread& ppu, vm::cptr<char> fmt,
|
|
|
|
|
ppu_va_args_t va_args)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2016-08-11 01:29:59 +02:00
|
|
|
sysPrxForUser.warning("_sys_printf(fmt=%s, ...)", fmt);
|
2015-08-02 04:15:49 +02:00
|
|
|
|
2018-03-01 11:48:42 +01:00
|
|
|
const auto buf = vm::make_str(ps3_fmt(ppu, fmt, va_args.count));
|
|
|
|
|
|
2021-09-11 12:05:43 +02:00
|
|
|
sys_tty_write(ppu, 0, buf, buf.get_count() - 1, vm::var<u32>{});
|
2015-07-28 22:05:44 +02:00
|
|
|
|
|
|
|
|
return CELL_OK;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
s32 _sys_sprintf(ppu_thread& ppu, vm::ptr<char> buffer, vm::cptr<char> fmt,
|
|
|
|
|
ppu_va_args_t va_args)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2017-03-25 22:25:28 +01:00
|
|
|
sysPrxForUser.warning("_sys_sprintf(buffer=*0x%x, fmt=%s, ...)", buffer, fmt);
|
|
|
|
|
|
|
|
|
|
std::string result = ps3_fmt(ppu, fmt, va_args.count);
|
|
|
|
|
|
|
|
|
|
std::memcpy(buffer.get_ptr(), result.c_str(), result.size() + 1);
|
|
|
|
|
|
|
|
|
|
return static_cast<s32>(result.size());
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 12:14:57 +02:00
|
|
|
error_code _sys_vprintf()
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2019-09-02 13:41:57 +02:00
|
|
|
sysPrxForUser.todo("_sys_vprintf()");
|
|
|
|
|
return CELL_OK;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 12:14:57 +02:00
|
|
|
error_code _sys_vsnprintf()
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2019-09-02 13:41:57 +02:00
|
|
|
sysPrxForUser.todo("_sys_vsnprintf()");
|
|
|
|
|
return CELL_OK;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2020-07-16 12:14:57 +02:00
|
|
|
error_code _sys_vsprintf()
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2019-09-02 13:41:57 +02:00
|
|
|
sysPrxForUser.todo("_sys_vsprintf()");
|
|
|
|
|
return CELL_OK;
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
void _sys_qsort(vm::ptr<void> base, u32 nelem, u32 size,
|
|
|
|
|
vm::ptr<qsortcmp> cmp)
|
2015-08-02 04:15:49 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
sysPrxForUser.warning(
|
|
|
|
|
"_sys_qsort(base=*0x%x, nelem=%d, size=0x%x, cmp=*0x%x)", base, nelem,
|
|
|
|
|
size, cmp);
|
2018-02-20 21:24:47 +01:00
|
|
|
|
|
|
|
|
static thread_local decltype(cmp) g_tls_cmp;
|
|
|
|
|
g_tls_cmp = cmp;
|
|
|
|
|
|
2025-04-08 18:46:57 +02:00
|
|
|
std::qsort(
|
|
|
|
|
base.get_ptr(), nelem, size, [](const void* a, const void* b) -> s32
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
2025-04-08 18:46:57 +02:00
|
|
|
return g_tls_cmp(static_cast<ppu_thread&>(*get_current_cpu_thread()),
|
|
|
|
|
vm::get_addr(a), vm::get_addr(b));
|
2025-04-05 21:50:45 +02:00
|
|
|
});
|
2015-08-02 04:15:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void sysPrxForUser_sys_libc_init()
|
|
|
|
|
{
|
2017-09-17 10:25:27 +02:00
|
|
|
REG_FUNC(sysPrxForUser, __sys_look_ctype_table);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_tolower);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_toupper);
|
|
|
|
|
|
2015-08-02 04:15:49 +02:00
|
|
|
REG_FUNC(sysPrxForUser, _sys_memset);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memcpy);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memcmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memchr);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memmove);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strlen);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strcmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strcat);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strchr);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncat);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strcpy);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncpy);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strncasecmp);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_strrchr);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_malloc);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_memalign);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_free);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_snprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_printf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_sprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_vprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_vsnprintf);
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_vsprintf);
|
|
|
|
|
|
|
|
|
|
REG_FUNC(sysPrxForUser, _sys_qsort);
|
|
|
|
|
}
|