libcubescript/src/lib_str.cc

237 lines
8.1 KiB
C++
Raw Normal View History

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