2017-02-08 00:07:35 +00:00
|
|
|
#include <functional>
|
2021-03-20 05:18:31 +00:00
|
|
|
#include <iterator>
|
2016-08-17 17:20:19 +00:00
|
|
|
|
2017-06-20 19:21:39 +00:00
|
|
|
#include <cubescript/cubescript.hh>
|
2016-08-02 00:21:36 +00:00
|
|
|
|
2021-03-23 00:11:21 +00:00
|
|
|
#include "cs_std.hh"
|
2021-03-23 00:25:47 +00:00
|
|
|
#include "cs_strman.hh"
|
2021-03-25 00:37:13 +00:00
|
|
|
#include "cs_thread.hh"
|
2021-03-18 22:56:16 +00:00
|
|
|
|
2021-03-23 22:32:25 +00:00
|
|
|
namespace cubescript {
|
2016-08-02 00:21:36 +00:00
|
|
|
|
2016-08-17 17:20:19 +00:00
|
|
|
template<typename F>
|
2021-03-23 22:29:32 +00:00
|
|
|
static inline void str_cmp_by(
|
2021-04-11 01:32:14 +00:00
|
|
|
state &cs, std::span<any_value> args, any_value &res, F cfunc
|
2021-03-20 04:41:25 +00:00
|
|
|
) {
|
2016-08-17 17:20:19 +00:00
|
|
|
bool val;
|
|
|
|
if (args.size() >= 2) {
|
2021-04-11 01:32:14 +00:00
|
|
|
val = cfunc(args[0].get_string(cs), args[1].get_string(cs));
|
2017-01-25 01:09:50 +00:00
|
|
|
for (size_t i = 2; (i < args.size()) && val; ++i) {
|
2021-04-11 01:32:14 +00:00
|
|
|
val = cfunc(args[i - 1].get_string(cs), args[i].get_string(cs));
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
2016-08-17 17:21:24 +00:00
|
|
|
val = cfunc(
|
2021-04-11 01:32:14 +00:00
|
|
|
!args.empty() ? args[0].get_string(cs) : std::string_view(),
|
2021-03-20 01:26:37 +00:00
|
|
|
std::string_view()
|
2016-08-17 17:21:24 +00:00
|
|
|
);
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_integer(integer_type(val));
|
2021-03-30 23:35:02 +00:00
|
|
|
}
|
2016-08-17 17:20:19 +00:00
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
LIBCUBESCRIPT_EXPORT void std_init_string(state &cs) {
|
|
|
|
new_cmd_quiet(cs, "strstr", "ss", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
std::string_view a = args[0].get_string(ccs);
|
|
|
|
std::string_view b = args[1].get_string(ccs);
|
2021-03-20 01:26:37 +00:00
|
|
|
auto pos = a.find(b);
|
|
|
|
if (pos == a.npos) {
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_integer(-1);
|
2021-03-20 01:26:37 +00:00
|
|
|
} else {
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_integer(integer_type(pos));
|
2016-08-02 00:21:36 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "strlen", "s", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_integer(integer_type(args[0].get_string(ccs).size()));
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "strcode", "si", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
std::string_view str = args[0].get_string(ccs);
|
2021-04-05 22:54:46 +00:00
|
|
|
integer_type i = args[1].get_integer();
|
2021-03-23 22:29:32 +00:00
|
|
|
if (i >= integer_type(str.size())) {
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_integer(0);
|
2016-08-02 00:21:36 +00:00
|
|
|
} else {
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_integer(static_cast<unsigned char>(str[i]));
|
2016-08-02 00:21:36 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "codestr", "i", [](auto &ccs, auto args, auto &res) {
|
2021-04-05 22:54:46 +00:00
|
|
|
char const p[2] = { char(args[0].get_integer()), '\0' };
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_string(std::string_view{static_cast<char const *>(p)}, ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "strlower", "s", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
auto inps = args[0].get_string(ccs);
|
2021-04-05 02:10:39 +00:00
|
|
|
auto *ics = state_p{ccs}.ts().istate;
|
2021-03-19 00:31:34 +00:00
|
|
|
auto *buf = ics->strman->alloc_buf(inps.size());
|
2021-03-20 05:18:31 +00:00
|
|
|
for (std::size_t i = 0; i < inps.size(); ++i) {
|
2021-04-05 23:10:49 +00:00
|
|
|
buf[i] = char(tolower(inps.data()[i]));
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_string(ics->strman->steal(buf));
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "strupper", "s", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
auto inps = args[0].get_string(ccs);
|
2021-04-05 02:10:39 +00:00
|
|
|
auto *ics = state_p{ccs}.ts().istate;
|
2021-03-19 00:31:34 +00:00
|
|
|
auto *buf = ics->strman->alloc_buf(inps.size());
|
2021-03-20 05:18:31 +00:00
|
|
|
for (std::size_t i = 0; i < inps.size(); ++i) {
|
2021-04-05 23:10:49 +00:00
|
|
|
buf[i] = char(toupper(inps.data()[i]));
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_string(ics->strman->steal(buf));
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "escape", "s", [](auto &ccs, auto args, auto &res) {
|
2021-03-23 22:29:32 +00:00
|
|
|
charbuf s{ccs};
|
2021-04-11 01:32:14 +00:00
|
|
|
escape_string(std::back_inserter(s), args[0].get_string(ccs));
|
|
|
|
res.set_string(s.str(), ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "unescape", "s", [](auto &ccs, auto args, auto &res) {
|
2021-03-23 22:29:32 +00:00
|
|
|
charbuf s{ccs};
|
2021-04-11 01:32:14 +00:00
|
|
|
unescape_string(std::back_inserter(s), args[0].get_string(ccs));
|
|
|
|
res.set_string(s.str(), ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "concat", "V", [](auto &ccs, auto args, auto &res) {
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_string(concat_values(ccs, args, " "));
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "concatword", "V", [](auto &ccs, auto args, auto &res) {
|
2021-04-05 22:54:46 +00:00
|
|
|
res.set_string(concat_values(ccs, args));
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "format", "V", [](auto &ccs, auto args, auto &res) {
|
2016-08-17 17:20:19 +00:00
|
|
|
if (args.empty()) {
|
2016-08-02 00:21:36 +00:00
|
|
|
return;
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
2021-03-23 22:29:32 +00:00
|
|
|
charbuf s{ccs};
|
2021-04-11 01:32:14 +00:00
|
|
|
string_ref fs = args[0].get_string(ccs);
|
2021-03-20 01:26:37 +00:00
|
|
|
std::string_view f{fs};
|
|
|
|
for (auto it = f.begin(); it != f.end(); ++it) {
|
|
|
|
char c = *it;
|
|
|
|
++it;
|
|
|
|
if ((c == '%') && (it != f.end())) {
|
|
|
|
char ic = *it;
|
|
|
|
++it;
|
|
|
|
if ((ic >= '1') && (ic <= '9')) {
|
2016-08-02 00:21:36 +00:00
|
|
|
int i = ic - '0';
|
2021-03-20 01:26:37 +00:00
|
|
|
if (std::size_t(i) < args.size()) {
|
2021-04-11 01:32:14 +00:00
|
|
|
s.append(args[i].get_string(ccs));
|
2016-09-15 21:04:32 +00:00
|
|
|
}
|
2016-08-17 17:20:19 +00:00
|
|
|
} else {
|
2021-03-19 01:50:48 +00:00
|
|
|
s.push_back(ic);
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-03-19 01:50:48 +00:00
|
|
|
s.push_back(c);
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
2016-08-02 00:21:36 +00:00
|
|
|
}
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_string(s.str(), ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "tohex", "ii", [](auto &ccs, auto args, auto &res) {
|
2021-03-20 05:52:10 +00:00
|
|
|
char buf[32];
|
|
|
|
/* use long long as the largest signed integer type */
|
2021-04-05 22:54:46 +00:00
|
|
|
auto val = static_cast<long long>(args[0].get_integer());
|
|
|
|
int prec = std::max(int(args[1].get_integer()), 1);
|
2021-03-20 05:52:10 +00:00
|
|
|
int n = snprintf(buf, sizeof(buf), "0x%.*llX", prec, val);
|
|
|
|
if (n >= int(sizeof(buf))) {
|
2021-03-23 22:29:32 +00:00
|
|
|
charbuf s{ccs};
|
2021-03-20 05:52:10 +00:00
|
|
|
s.reserve(n + 1);
|
|
|
|
s.data()[0] = '\0';
|
|
|
|
int nn = snprintf(s.data(), n + 1, "0x%.*llX", prec, val);
|
|
|
|
if ((nn > 0) && (nn <= n)) {
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_string(
|
|
|
|
std::string_view{s.data(), std::size_t(nn)}, ccs
|
|
|
|
);
|
2021-03-20 05:52:10 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (n > 0) {
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_string(static_cast<char const *>(buf), ccs);
|
2021-03-20 05:52:10 +00:00
|
|
|
return;
|
2017-02-12 21:52:43 +00:00
|
|
|
}
|
2021-03-20 05:52:10 +00:00
|
|
|
/* should pretty much be unreachable */
|
2021-03-23 22:29:32 +00:00
|
|
|
throw internal_error{"format error"};
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "substr", "siiN", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
std::string_view s = args[0].get_string(ccs);
|
2021-04-05 22:54:46 +00:00
|
|
|
auto start = args[1].get_integer(), count = args[2].get_integer();
|
|
|
|
auto numargs = args[3].get_integer();
|
|
|
|
auto len = integer_type(s.size());
|
|
|
|
auto offset = std::clamp(start, integer_type(0), len);
|
|
|
|
res.set_string(std::string_view{
|
2016-08-02 00:21:36 +00:00
|
|
|
&s[offset],
|
2021-03-20 01:26:37 +00:00
|
|
|
((numargs >= 3)
|
2021-03-23 22:29:32 +00:00
|
|
|
? size_t(std::clamp(count, integer_type(0), len - offset))
|
2021-03-18 23:01:57 +00:00
|
|
|
: size_t(len - offset))
|
2021-04-11 01:32:14 +00:00
|
|
|
}, ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "strcmp", "s1V", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
str_cmp_by(ccs, args, res, std::equal_to<std::string_view>());
|
2016-08-17 17:20:19 +00:00
|
|
|
});
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "=s", "s1V", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
str_cmp_by(ccs, args, res, std::equal_to<std::string_view>());
|
2016-08-17 17:20:19 +00:00
|
|
|
});
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "!=s", "s1V", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
str_cmp_by(ccs, args, res, std::not_equal_to<std::string_view>());
|
2016-08-17 17:20:19 +00:00
|
|
|
});
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "<s", "s1V", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
str_cmp_by(ccs, args, res, std::less<std::string_view>());
|
2016-08-17 17:20:19 +00:00
|
|
|
});
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, ">s", "s1V", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
str_cmp_by(ccs, args, res, std::greater<std::string_view>());
|
2016-08-17 17:20:19 +00:00
|
|
|
});
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "<=s", "s1V", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
str_cmp_by(ccs, args, res, std::less_equal<std::string_view>());
|
2016-08-17 17:20:19 +00:00
|
|
|
});
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, ">=s", "s1V", [](auto &ccs, auto args, auto &res) {
|
2021-04-11 01:32:14 +00:00
|
|
|
str_cmp_by(ccs, args, res, std::greater_equal<std::string_view>());
|
2016-08-17 17:20:19 +00:00
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "strreplace", "ssss", [](
|
|
|
|
auto &ccs, auto args, auto &res
|
|
|
|
) {
|
2021-04-11 01:32:14 +00:00
|
|
|
std::string_view s = args[0].get_string(ccs);
|
|
|
|
std::string_view oldval = args[1].get_string(ccs),
|
|
|
|
newval = args[2].get_string(ccs),
|
|
|
|
newval2 = args[3].get_string(ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
if (newval2.empty()) {
|
|
|
|
newval2 = newval;
|
|
|
|
}
|
2021-03-20 01:26:37 +00:00
|
|
|
if (oldval.empty()) {
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_string(s, ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-03-23 22:29:32 +00:00
|
|
|
charbuf buf{ccs};
|
2017-01-25 01:09:50 +00:00
|
|
|
for (size_t i = 0;; ++i) {
|
2021-03-20 01:26:37 +00:00
|
|
|
auto p = s.find(oldval);
|
|
|
|
if (p == s.npos) {
|
2021-03-19 01:50:48 +00:00
|
|
|
buf.append(s);
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_string(s, ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-03-20 01:26:37 +00:00
|
|
|
buf.append(s.substr(0, p));
|
|
|
|
buf.append((i & 1) ? newval2 : newval);
|
|
|
|
buf.append(s.substr(
|
|
|
|
p + oldval.size(),
|
|
|
|
s.size() - p - oldval.size()
|
|
|
|
));
|
2016-08-02 00:21:36 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-04-11 17:36:20 +00:00
|
|
|
new_cmd_quiet(cs, "strsplice", "ssii", [](
|
|
|
|
auto &ccs, auto args, auto &res
|
|
|
|
) {
|
2021-04-11 01:32:14 +00:00
|
|
|
std::string_view s = args[0].get_string(ccs);
|
|
|
|
std::string_view vals = args[1].get_string(ccs);
|
2021-04-05 22:54:46 +00:00
|
|
|
integer_type skip = args[2].get_integer(),
|
|
|
|
count = args[3].get_integer();
|
2021-03-23 22:29:32 +00:00
|
|
|
integer_type offset = std::clamp(skip, integer_type(0), integer_type(s.size())),
|
|
|
|
len = std::clamp(count, integer_type(0), integer_type(s.size()) - offset);
|
|
|
|
charbuf p{ccs};
|
2016-09-15 21:04:32 +00:00
|
|
|
p.reserve(s.size() - len + vals.size());
|
2016-08-17 17:20:19 +00:00
|
|
|
if (offset) {
|
2021-03-20 01:26:37 +00:00
|
|
|
p.append(s.substr(0, offset));
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
2021-03-19 01:50:48 +00:00
|
|
|
p.append(vals);
|
2021-03-23 22:29:32 +00:00
|
|
|
if ((offset + len) < integer_type(s.size())) {
|
2021-03-20 01:26:37 +00:00
|
|
|
p.append(s.substr(offset + len, s.size() - offset - len));
|
2016-08-17 17:20:19 +00:00
|
|
|
}
|
2021-04-11 01:32:14 +00:00
|
|
|
res.set_string(p.str(), ccs);
|
2016-08-02 00:21:36 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-03-23 22:32:25 +00:00
|
|
|
} /* namespace cubescript */
|