drop libostd requirement entirely
parent
cb926a5750
commit
82d366366e
28
README.md
28
README.md
|
@ -27,8 +27,8 @@ advantages, including:
|
||||||
|
|
||||||
* Independent implementation (can be embedded in any project)
|
* Independent implementation (can be embedded in any project)
|
||||||
* No global state (multiple CubeScripts in a single program)
|
* No global state (multiple CubeScripts in a single program)
|
||||||
* Modern C++17 API (no macros, use of strongly typed enums, lambdas, ranges etc.)
|
* Modern C++20 API
|
||||||
* C++17 lambdas can be used as commands (including captures and type inference)
|
* C++ lambdas can be used as commands (including captures and type inference)
|
||||||
* Error handling including recovery (protected call system similar to Lua)
|
* Error handling including recovery (protected call system similar to Lua)
|
||||||
* Stricter parsing (strings cannot be left unfinished etc.)
|
* Stricter parsing (strings cannot be left unfinished etc.)
|
||||||
* Loop control statements (`break` and `continue`)
|
* Loop control statements (`break` and `continue`)
|
||||||
|
@ -70,13 +70,8 @@ utilized in the outside native code.
|
||||||
|
|
||||||
## Building and usage
|
## Building and usage
|
||||||
|
|
||||||
The only dependency is libostd:
|
There are no dependencies (other than a suitable compiler and the standard
|
||||||
|
library).
|
||||||
https://git.octaforge.org/OctaForge/libostd
|
|
||||||
|
|
||||||
https://github.com/OctaForge/libostd
|
|
||||||
|
|
||||||
If libostd can work on your system, so can libcubescript.
|
|
||||||
|
|
||||||
Libostd is built using Meson. Therefore, you need to install Meson and then
|
Libostd is built using Meson. Therefore, you need to install Meson and then
|
||||||
you can compile it as usual. Typically, this will be something like
|
you can compile it as usual. Typically, this will be something like
|
||||||
|
@ -84,16 +79,17 @@ you can compile it as usual. Typically, this will be something like
|
||||||
~~~
|
~~~
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
meson ..
|
meson ..
|
||||||
meson compile
|
ninja all
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
Link the libcubescript library together with your application and everything should just work.
|
Link the libcubescript library together with your application and everything
|
||||||
It also builds the REPL.
|
should just work. It also builds the REPL.
|
||||||
|
|
||||||
The project also bundles the linenoise line editing library which has been modified
|
The project also bundles the linenoise line editing library which has been
|
||||||
to compile cleanly as C++ (with the same flags as libcubescript). It's used strictly
|
modified to compile cleanly as C++ (with the same flags as libcubescript).
|
||||||
for the REPL only (you don't need it to build libcubescript itself). The version
|
It's used strictly for the REPL only (you don't need it to build libcubescript
|
||||||
in the repository tracks Git revision https://github.com/antirez/linenoise/commit/c894b9e59f02203dbe4e2be657572cf88c4230c3.
|
itself). The version in the repository tracks Git revision
|
||||||
|
https://github.com/antirez/linenoise/commit/c894b9e59f02203dbe4e2be657572cf88c4230c3.
|
||||||
|
|
||||||
## Licensing
|
## Licensing
|
||||||
|
|
||||||
|
|
|
@ -598,12 +598,12 @@ struct cs_error {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...A>
|
template<typename ...A>
|
||||||
cs_error(cs_state &cs, std::string_view msg, A &&...args):
|
cs_error(cs_state &cs, std::string_view msg, A const &...args):
|
||||||
p_errmsg(), p_stack(cs)
|
p_errmsg(), p_stack(cs)
|
||||||
{
|
{
|
||||||
char fbuf[512];
|
char fbuf[512];
|
||||||
int written = std::snprintf(
|
int written = std::snprintf(
|
||||||
fbuf, sizeof(fbuf), "%.*s", int(msg.size()), msg.data()
|
fbuf, sizeof(fbuf), msg.data(), args...
|
||||||
);
|
);
|
||||||
if (written >= int(sizeof(fbuf))) {
|
if (written >= int(sizeof(fbuf))) {
|
||||||
written = std::strlen(fbuf);
|
written = std::strlen(fbuf);
|
||||||
|
|
14
src/cs_vm.cc
14
src/cs_vm.cc
|
@ -110,8 +110,8 @@ cs_stack_state cs_error::save_stack(cs_state &cs) {
|
||||||
std::string_view cs_error::save_msg(
|
std::string_view cs_error::save_msg(
|
||||||
cs_state &cs, std::string_view msg
|
cs_state &cs, std::string_view msg
|
||||||
) {
|
) {
|
||||||
if (msg.size() > sizeof(cs.p_errbuf)) {
|
if (msg.size() >= sizeof(cs.p_errbuf)) {
|
||||||
msg = msg.substr(0, sizeof(cs.p_errbuf));
|
msg = msg.substr(0, sizeof(cs.p_errbuf) - 1);
|
||||||
}
|
}
|
||||||
cs_gen_state *gs = cs.p_pstate;
|
cs_gen_state *gs = cs.p_pstate;
|
||||||
if (gs) {
|
if (gs) {
|
||||||
|
@ -137,6 +137,7 @@ std::string_view cs_error::save_msg(
|
||||||
return std::string_view{cs.p_errbuf, std::size_t(sz)};
|
return std::string_view{cs.p_errbuf, std::size_t(sz)};
|
||||||
}
|
}
|
||||||
memcpy(cs.p_errbuf, msg.data(), msg.size());
|
memcpy(cs.p_errbuf, msg.data(), msg.size());
|
||||||
|
cs.p_errbuf[msg.size()] = '\0';
|
||||||
return std::string_view{cs.p_errbuf, msg.size()};
|
return std::string_view{cs.p_errbuf, msg.size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +528,7 @@ struct RunDepthRef {
|
||||||
static inline cs_alias *cs_get_lookup_id(cs_state &cs, uint32_t op) {
|
static inline cs_alias *cs_get_lookup_id(cs_state &cs, uint32_t op) {
|
||||||
cs_ident *id = cs.p_state->identmap[op >> 8];
|
cs_ident *id = cs.p_state->identmap[op >> 8];
|
||||||
if (id->get_flags() & CS_IDF_UNKNOWN) {
|
if (id->get_flags() & CS_IDF_UNKNOWN) {
|
||||||
throw cs_error(cs, "unknown alias lookup: %s", id->get_name());
|
throw cs_error(cs, "unknown alias lookup: %s", id->get_name().data());
|
||||||
}
|
}
|
||||||
return static_cast<cs_alias *>(id);
|
return static_cast<cs_alias *>(id);
|
||||||
}
|
}
|
||||||
|
@ -574,7 +575,7 @@ static inline int cs_get_lookupu_type(
|
||||||
return CsIdUnknown;
|
return CsIdUnknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw cs_error(cs, "unknown alias lookup: %s", arg.get_str());
|
throw cs_error(cs, "unknown alias lookup: %s", arg.get_str().data());
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t *runcode(cs_state &cs, uint32_t *code, cs_value &result) {
|
static uint32_t *runcode(cs_state &cs, uint32_t *code, cs_value &result) {
|
||||||
|
@ -1421,7 +1422,7 @@ static uint32_t *runcode(cs_state &cs, uint32_t *code, cs_value &result) {
|
||||||
if (id->get_flags() & CS_IDF_UNKNOWN) {
|
if (id->get_flags() & CS_IDF_UNKNOWN) {
|
||||||
force_arg(result, op & CS_CODE_RET_MASK);
|
force_arg(result, op & CS_CODE_RET_MASK);
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
cs, "unknown command: %s", id->get_name()
|
cs, "unknown command: %s", id->get_name().data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
cs_call_alias(
|
cs_call_alias(
|
||||||
|
@ -1471,8 +1472,9 @@ noid:
|
||||||
}
|
}
|
||||||
result.force_none();
|
result.force_none();
|
||||||
force_arg(result, op & CS_CODE_RET_MASK);
|
force_arg(result, op & CS_CODE_RET_MASK);
|
||||||
|
std::string_view ids{idn};
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
cs, "unknown command: %s", std::string_view{idn}
|
cs, "unknown command: %s", ids.data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
result.force_none();
|
result.force_none();
|
||||||
|
|
|
@ -474,7 +474,7 @@ LIBCUBESCRIPT_EXPORT cs_ident *cs_state::new_ident(std::string_view name, int fl
|
||||||
if (!id) {
|
if (!id) {
|
||||||
if (cs_check_num(name)) {
|
if (cs_check_num(name)) {
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
*this, "number %s is not a valid identifier name", name
|
*this, "number %s is not a valid identifier name", name.data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
id = add_ident(p_state->create<cs_alias>(
|
id = add_ident(p_state->create<cs_alias>(
|
||||||
|
@ -560,10 +560,10 @@ LIBCUBESCRIPT_EXPORT cs_svar *cs_state::new_svar(
|
||||||
LIBCUBESCRIPT_EXPORT void cs_state::reset_var(std::string_view name) {
|
LIBCUBESCRIPT_EXPORT void cs_state::reset_var(std::string_view name) {
|
||||||
cs_ident *id = get_ident(name);
|
cs_ident *id = get_ident(name);
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw cs_error(*this, "variable %s does not exist", name);
|
throw cs_error(*this, "variable %s does not exist", name.data());
|
||||||
}
|
}
|
||||||
if (id->get_flags() & CS_IDF_READONLY) {
|
if (id->get_flags() & CS_IDF_READONLY) {
|
||||||
throw cs_error(*this, "variable %s is read only", name);
|
throw cs_error(*this, "variable %s is read only", name.data());
|
||||||
}
|
}
|
||||||
clear_override(*id);
|
clear_override(*id);
|
||||||
}
|
}
|
||||||
|
@ -600,11 +600,11 @@ LIBCUBESCRIPT_EXPORT void cs_state::set_alias(std::string_view name, cs_value v)
|
||||||
default:
|
default:
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
*this, "cannot redefine builtin %s with an alias",
|
*this, "cannot redefine builtin %s with an alias",
|
||||||
id->get_name()
|
id->get_name().data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (cs_check_num(name)) {
|
} else if (cs_check_num(name)) {
|
||||||
throw cs_error(*this, "cannot alias number %s", name);
|
throw cs_error(*this, "cannot alias number %s", name.data());
|
||||||
} else {
|
} else {
|
||||||
add_ident(p_state->create<cs_alias>(
|
add_ident(p_state->create<cs_alias>(
|
||||||
*this, cs_strref{*p_state, name}, std::move(v), identflags
|
*this, cs_strref{*p_state, name}, std::move(v), identflags
|
||||||
|
@ -657,7 +657,8 @@ static inline void cs_override_var(cs_state &cs, cs_var *v, int &vflags, SF sf)
|
||||||
if ((cs.identflags & CS_IDF_OVERRIDDEN) || (vflags & CS_IDF_OVERRIDE)) {
|
if ((cs.identflags & CS_IDF_OVERRIDDEN) || (vflags & CS_IDF_OVERRIDE)) {
|
||||||
if (vflags & CS_IDF_PERSIST) {
|
if (vflags & CS_IDF_PERSIST) {
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
cs, "cannot override persistent variable '%s'", v->get_name()
|
cs, "cannot override persistent variable '%s'",
|
||||||
|
v->get_name().data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!(vflags & CS_IDF_OVERRIDDEN)) {
|
if (!(vflags & CS_IDF_OVERRIDDEN)) {
|
||||||
|
@ -825,14 +826,14 @@ cs_int cs_clamp_var(cs_state &cs, cs_ivar *iv, cs_int v) {
|
||||||
: "valid range for '%s' is 0x%X..0x%X"
|
: "valid range for '%s' is 0x%X..0x%X"
|
||||||
)
|
)
|
||||||
: "valid range for '%s' is %d..%d",
|
: "valid range for '%s' is %d..%d",
|
||||||
iv->get_name(), iv->get_val_min(), iv->get_val_max()
|
iv->get_name().data(), iv->get_val_min(), iv->get_val_max()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBCUBESCRIPT_EXPORT void cs_state::set_var_int_checked(cs_ivar *iv, cs_int v) {
|
LIBCUBESCRIPT_EXPORT void cs_state::set_var_int_checked(cs_ivar *iv, cs_int v) {
|
||||||
if (iv->get_flags() & CS_IDF_READONLY) {
|
if (iv->get_flags() & CS_IDF_READONLY) {
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
*this, "variable '%s' is read only", iv->get_name()
|
*this, "variable '%s' is read only", iv->get_name().data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
cs_override_var(
|
cs_override_var(
|
||||||
|
@ -871,7 +872,7 @@ cs_float cs_clamp_fvar(cs_state &cs, cs_fvar *fv, cs_float v) {
|
||||||
vmin.set_float(fv->get_val_min());
|
vmin.set_float(fv->get_val_min());
|
||||||
vmax.set_float(fv->get_val_max());
|
vmax.set_float(fv->get_val_max());
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
cs, "valid range for '%s' is %s..%s", fv->get_name(),
|
cs, "valid range for '%s' is %s..%s", fv->get_name().data(),
|
||||||
vmin.force_str(), vmax.force_str()
|
vmin.force_str(), vmax.force_str()
|
||||||
);
|
);
|
||||||
return v;
|
return v;
|
||||||
|
@ -880,7 +881,7 @@ cs_float cs_clamp_fvar(cs_state &cs, cs_fvar *fv, cs_float v) {
|
||||||
LIBCUBESCRIPT_EXPORT void cs_state::set_var_float_checked(cs_fvar *fv, cs_float v) {
|
LIBCUBESCRIPT_EXPORT void cs_state::set_var_float_checked(cs_fvar *fv, cs_float v) {
|
||||||
if (fv->get_flags() & CS_IDF_READONLY) {
|
if (fv->get_flags() & CS_IDF_READONLY) {
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
*this, "variable '%s' is read only", fv->get_name()
|
*this, "variable '%s' is read only", fv->get_name().data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
cs_override_var(
|
cs_override_var(
|
||||||
|
@ -899,7 +900,7 @@ LIBCUBESCRIPT_EXPORT void cs_state::set_var_str_checked(
|
||||||
) {
|
) {
|
||||||
if (sv->get_flags() & CS_IDF_READONLY) {
|
if (sv->get_flags() & CS_IDF_READONLY) {
|
||||||
throw cs_error(
|
throw cs_error(
|
||||||
*this, "variable '%s' is read only", sv->get_name()
|
*this, "variable '%s' is read only", sv->get_name().data()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
cs_override_var(
|
cs_override_var(
|
||||||
|
|
|
@ -14,11 +14,8 @@ libcubescript_src = [
|
||||||
'lib_str.cc'
|
'lib_str.cc'
|
||||||
]
|
]
|
||||||
|
|
||||||
libostd_dep = dependency('libostd', fallback: ['libostd', 'libostd_static'])
|
|
||||||
|
|
||||||
libcubescript_lib = both_libraries('cubescript',
|
libcubescript_lib = both_libraries('cubescript',
|
||||||
libcubescript_src,
|
libcubescript_src,
|
||||||
dependencies: libostd_dep,
|
|
||||||
include_directories: libcubescript_includes + [include_directories('.')],
|
include_directories: libcubescript_includes + [include_directories('.')],
|
||||||
cpp_args: extra_cxxflags,
|
cpp_args: extra_cxxflags,
|
||||||
install: true,
|
install: true,
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
[wrap-git]
|
|
||||||
directory = libostd
|
|
||||||
url = https://git.octaforge.org/OctaForge/libostd.git
|
|
||||||
revision = head
|
|
|
@ -2,15 +2,23 @@
|
||||||
/* use nothing (no line editing support) */
|
/* use nothing (no line editing support) */
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
#include <ostd/string.hh>
|
|
||||||
|
|
||||||
inline void init_lineedit(cs_state &, std::string_view) {
|
inline void init_lineedit(cs_state &, std::string_view) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::optional<std::string> read_line(cs_state &, cs_svar *pr) {
|
inline std::optional<std::string> read_line(cs_state &, cs_svar *pr) {
|
||||||
ostd::write(pr->get_value());
|
std::string lbuf;
|
||||||
return ostd::cin.get_line(ostd::appender<std::string>()).get();
|
char buf[512];
|
||||||
|
printf("%s", pr->get_value().data());
|
||||||
|
std::fflush(stdout);
|
||||||
|
while (fgets(buf, sizeof(buf), stdin)) {
|
||||||
|
lbuf += static_cast<char const *>(buf);
|
||||||
|
if (strchr(buf, '\n')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::move(lbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void add_history(cs_state &, std::string_view) {
|
inline void add_history(cs_state &, std::string_view) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifdef CS_REPL_USE_LINENOISE
|
#ifdef CS_REPL_USE_LINENOISE
|
||||||
#ifdef OSTD_PLATFORM_POSIX
|
#ifndef _WIN32
|
||||||
#ifndef CS_REPL_HAS_EDIT
|
#ifndef CS_REPL_HAS_EDIT
|
||||||
#define CS_REPL_HAS_EDIT
|
#define CS_REPL_HAS_EDIT
|
||||||
/* use the bundled linenoise library, default */
|
/* use the bundled linenoise library, default */
|
||||||
|
@ -10,8 +10,6 @@
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include <ostd/string.hh>
|
|
||||||
|
|
||||||
#include "linenoise.hh"
|
#include "linenoise.hh"
|
||||||
|
|
||||||
static cs_state *ln_cs = nullptr;
|
static cs_state *ln_cs = nullptr;
|
||||||
|
|
|
@ -3,12 +3,9 @@
|
||||||
#define CS_REPL_HAS_EDIT
|
#define CS_REPL_HAS_EDIT
|
||||||
/* use the GNU readline library */
|
/* use the GNU readline library */
|
||||||
|
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include <ostd/string.hh>
|
|
||||||
|
|
||||||
#include <readline/readline.h>
|
#include <readline/readline.h>
|
||||||
#include <readline/history.h>
|
#include <readline/history.h>
|
||||||
|
|
||||||
|
@ -16,15 +13,14 @@ static cs_state *rd_cs = nullptr;
|
||||||
|
|
||||||
inline char *ln_complete_list(char const *buf, int state) {
|
inline char *ln_complete_list(char const *buf, int state) {
|
||||||
static std::string_view cmd;
|
static std::string_view cmd;
|
||||||
static ostd::iterator_range<cs_ident **> itr;
|
static std::span<cs_ident *> itr;
|
||||||
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
cmd = get_complete_cmd(buf);
|
cmd = get_complete_cmd(buf);
|
||||||
itr = rd_cs->get_idents();
|
itr = rd_cs->get_idents();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; !itr.empty(); itr.pop_front()) {
|
for (cs_ident *id: itr) {
|
||||||
cs_ident *id = itr.front();
|
|
||||||
if (!id->is_command()) {
|
if (!id->is_command()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -33,7 +29,7 @@ inline char *ln_complete_list(char const *buf, int state) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (idname.substr(0, cmd.size()) == cmd) {
|
if (idname.substr(0, cmd.size()) == cmd) {
|
||||||
itr.pop_front();
|
++itr;
|
||||||
return strdup(idname.data());
|
return strdup(idname.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ repl_src = [
|
||||||
'repl.cc'
|
'repl.cc'
|
||||||
]
|
]
|
||||||
|
|
||||||
repl_deps = [libostd_dep, libcubescript]
|
repl_deps = [libcubescript]
|
||||||
repl_flags = []
|
repl_flags = []
|
||||||
|
|
||||||
if get_option('readline')
|
if get_option('readline')
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
#include <ostd/platform.hh>
|
|
||||||
#include <ostd/io.hh>
|
|
||||||
#include <ostd/string.hh>
|
|
||||||
|
|
||||||
#include <cubescript/cubescript.hh>
|
#include <cubescript/cubescript.hh>
|
||||||
|
|
||||||
using namespace cscript;
|
using namespace cscript;
|
||||||
|
@ -16,7 +15,7 @@ std::string_view version = "CubeScript 0.0.1";
|
||||||
|
|
||||||
/* util */
|
/* util */
|
||||||
|
|
||||||
#ifdef OSTD_PLATFORM_WIN32
|
#if defined(_WIN32)
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
static bool stdin_is_tty() {
|
static bool stdin_is_tty() {
|
||||||
return _isatty(_fileno(stdin));
|
return _isatty(_fileno(stdin));
|
||||||
|
@ -165,9 +164,9 @@ inline cs_command *get_hint_cmd(cs_state &cs, std::string_view buf) {
|
||||||
/* usage */
|
/* usage */
|
||||||
|
|
||||||
void print_usage(std::string_view progname, bool err) {
|
void print_usage(std::string_view progname, bool err) {
|
||||||
auto &s = err ? ostd::cerr : ostd::cout;
|
std::fprintf(
|
||||||
s.writeln(
|
err ? stderr : stdout,
|
||||||
"Usage: ", progname, " [options] [file]\n"
|
"Usage: %s [options] [file]\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -e str run string \"str\"\n"
|
" -e str run string \"str\"\n"
|
||||||
" -i enter interactive mode after the above\n"
|
" -i enter interactive mode after the above\n"
|
||||||
|
@ -175,12 +174,13 @@ void print_usage(std::string_view progname, bool err) {
|
||||||
" -h show this message\n"
|
" -h show this message\n"
|
||||||
" -- stop handling options\n"
|
" -- stop handling options\n"
|
||||||
" - execute stdin and stop handling options"
|
" - execute stdin and stop handling options"
|
||||||
|
"\n",
|
||||||
|
progname.data()
|
||||||
);
|
);
|
||||||
s.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_version() {
|
void print_version() {
|
||||||
ostd::writeln(version);
|
printf("%s\n", version.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
static cs_state *scs = nullptr;
|
static cs_state *scs = nullptr;
|
||||||
|
@ -200,33 +200,35 @@ static void repl_print_var(cs_state const &cs, cs_var const &var) {
|
||||||
auto &iv = static_cast<cs_ivar const &>(var);
|
auto &iv = static_cast<cs_ivar const &>(var);
|
||||||
auto val = iv.get_value();
|
auto val = iv.get_value();
|
||||||
if (!(iv.get_flags() & CS_IDF_HEX) || (val < 0)) {
|
if (!(iv.get_flags() & CS_IDF_HEX) || (val < 0)) {
|
||||||
ostd::writefln("%s = %d", iv.get_name(), val);
|
std::printf("%s = %d\n", iv.get_name().data(), val);
|
||||||
} else if (iv.get_val_max() == 0xFFFFFF) {
|
} else if (iv.get_val_max() == 0xFFFFFF) {
|
||||||
ostd::writefln(
|
std::printf(
|
||||||
"%s = 0x%.6X (%d, %d, %d)", iv.get_name(),
|
"%s = 0x%.6X (%d, %d, %d)\n",
|
||||||
|
iv.get_name().data(),
|
||||||
val, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF
|
val, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ostd::writefln("%s = 0x%X", iv.get_name(), val);
|
std::printf("%s = 0x%X\n", iv.get_name().data(), val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case cs_ident_type::FVAR: {
|
case cs_ident_type::FVAR: {
|
||||||
auto &fv = static_cast<cs_fvar const &>(var);
|
auto &fv = static_cast<cs_fvar const &>(var);
|
||||||
auto val = fv.get_value();
|
auto val = fv.get_value();
|
||||||
ostd::writefln(
|
if (std::floor(val) == val) {
|
||||||
(floor(val) == val) ? "%s = %.1f" : "%s = %.7g",
|
std::printf("%s = %.1f", fv.get_name().data(), val);
|
||||||
fv.get_name(), val
|
} else {
|
||||||
);
|
std::printf("%s = %.7g", fv.get_name().data(), val);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case cs_ident_type::SVAR: {
|
case cs_ident_type::SVAR: {
|
||||||
auto &sv = static_cast<cs_svar const &>(var);
|
auto &sv = static_cast<cs_svar const &>(var);
|
||||||
auto val = std::string_view{sv.get_value()};
|
auto val = std::string_view{sv.get_value()};
|
||||||
if (val.find('"') == val.npos) {
|
if (val.find('"') == val.npos) {
|
||||||
ostd::writefln("%s = \"%s\"", sv.get_name(), val);
|
std::printf("%s = \"%s\"", sv.get_name().data(), val.data());
|
||||||
} else {
|
} else {
|
||||||
ostd::writefln("%s = [%s]", sv.get_name(), val);
|
std::printf("%s = [%s]", sv.get_name().data(), val.data());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -236,28 +238,29 @@ static void repl_print_var(cs_state const &cs, cs_var const &var) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool do_run_file(cs_state &cs, std::string_view fname, cs_value &ret) {
|
static bool do_run_file(cs_state &cs, std::string_view fname, cs_value &ret) {
|
||||||
std::unique_ptr<char[]> buf;
|
FILE *f = std::fopen(fname.data(), "rb");
|
||||||
std::size_t len;
|
if (!f) {
|
||||||
|
|
||||||
ostd::file_stream f{fname, ostd::stream_mode::READ};
|
|
||||||
if (!f.is_open()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = f.size();
|
std::fseek(f, 0, SEEK_END);
|
||||||
buf = std::make_unique<char[]>(len + 1);
|
auto len = std::ftell(f);
|
||||||
|
std::fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
auto buf = std::make_unique<char[]>(len + 1);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
|
std::fclose(f);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (std::fread(buf.get(), 1, len, f) != std::size_t(len)) {
|
||||||
f.get(buf.get(), len);
|
std::fclose(f);
|
||||||
} catch (...) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
|
|
||||||
cs.run(std::string_view{buf.get(), len}, ret, fname);
|
cs.run(std::string_view{buf.get(), std::size_t(len)}, ret, fname);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +271,7 @@ static bool do_call(cs_state &cs, std::string_view line, bool file = false) {
|
||||||
try {
|
try {
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!do_run_file(cs, line, ret)) {
|
if (!do_run_file(cs, line, ret)) {
|
||||||
ostd::cerr.writeln("cannot read file: ", line);
|
std::fprintf(stderr, "cannot read file: %s\n", line.data());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cs.run(line, ret);
|
cs.run(line, ret);
|
||||||
|
@ -291,18 +294,20 @@ static bool do_call(cs_state &cs, std::string_view line, bool file = false) {
|
||||||
if (!file && ((terr == "missing \"]\"") || (terr == "missing \")\""))) {
|
if (!file && ((terr == "missing \"]\"") || (terr == "missing \")\""))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ostd::writeln(!is_lnum ? "stdin: " : "stdin:", e.what());
|
std::printf(
|
||||||
|
"%s%s\n", !is_lnum ? "stdin: " : "stdin:", e.what().data()
|
||||||
|
);
|
||||||
if (e.get_stack().get()) {
|
if (e.get_stack().get()) {
|
||||||
std::string str;
|
std::string str;
|
||||||
cscript::util::print_stack(std::back_inserter(str), e.get_stack());
|
cscript::util::print_stack(std::back_inserter(str), e.get_stack());
|
||||||
ostd::writeln(str);
|
std::printf("%s\n", str.data());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
scs = nullptr;
|
scs = nullptr;
|
||||||
if (ret.get_type() != cs_value_type::NONE) {
|
if (ret.get_type() != cs_value_type::NONE) {
|
||||||
ostd::writeln(std::string_view{ret.get_str()});
|
std::printf("%s\n", std::string_view{ret.get_str()}.data());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -316,7 +321,7 @@ static void do_tty(cs_state &cs) {
|
||||||
do_exit = true;
|
do_exit = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
ostd::writeln(version, " (REPL mode)");
|
std::printf("%s (REPL mode)\n", version.data());
|
||||||
for (;;) {
|
for (;;) {
|
||||||
auto line = read_line(cs, prompt);
|
auto line = read_line(cs, prompt);
|
||||||
if (!line) {
|
if (!line) {
|
||||||
|
@ -364,7 +369,7 @@ int main(int argc, char **argv) {
|
||||||
});
|
});
|
||||||
|
|
||||||
gcs.new_command("echo", "C", [](auto &, auto args, auto &) {
|
gcs.new_command("echo", "C", [](auto &, auto args, auto &) {
|
||||||
ostd::writeln(std::string_view{args[0].get_str()});
|
std::printf("%s\n", std::string_view{args[0].get_str()}.data());
|
||||||
});
|
});
|
||||||
|
|
||||||
int firstarg = 0;
|
int firstarg = 0;
|
||||||
|
@ -450,7 +455,7 @@ endargs:
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
std::string str;
|
std::string str;
|
||||||
for (signed char c = '\0'; (c = ostd::cin.get_char()) != EOF;) {
|
for (signed char c = '\0'; (c = std::fgetc(stdin)) != EOF;) {
|
||||||
str += c;
|
str += c;
|
||||||
}
|
}
|
||||||
do_call(gcs, str);
|
do_call(gcs, str);
|
||||||
|
|
Loading…
Reference in New Issue