Update tools

This commit is contained in:
Joao Paulo Magalhaes
2025-09-28 19:08:28 +01:00
parent 4909b742b5
commit 83c163c162
3 changed files with 487 additions and 119 deletions

View File

@@ -6,10 +6,19 @@ c4_add_executable(ryml-parse-emit
c4_add_executable(ryml-yaml-events
SOURCES yaml_events.cpp
../test/test_suite/test_suite_events.hpp
../test/test_suite/test_suite_events_emitter.cpp
../test/test_suite/test_suite_event_handler.hpp
../test/test_suite/test_suite_event_handler.cpp
INC_DIRS ../test
../src_extra/c4/yml/extra/event_handler_ints.hpp
../src_extra/c4/yml/extra/event_handler_ints.cpp
../src_extra/c4/yml/extra/event_handler_testsuite.hpp
../src_extra/c4/yml/extra/event_handler_testsuite.cpp
../src_extra/c4/yml/extra/ints_utils.hpp
../src_extra/c4/yml/extra/ints_utils.cpp
../src_extra/c4/yml/extra/ints_to_testsuite.hpp
../src_extra/c4/yml/extra/ints_to_testsuite.cpp
../src_extra/c4/yml/extra/scalar.hpp
../src_extra/c4/yml/extra/scalar.cpp
../src_extra/c4/yml/extra/string.hpp
../test/testsuite/testsuite_events.hpp
../test/testsuite/testsuite_events_emitter.cpp
INC_DIRS ../test ../src_extra
LIBS ryml c4fs
FOLDER tools)

View File

@@ -4,7 +4,8 @@ from os.path import abspath, dirname
import sys
import subprocess
import argparse
from typing import List
from enum import Enum
projdir = abspath(dirname(dirname(__file__)))
sys.path.insert(0, f"{projdir}/ext/c4core/cmake")
@@ -12,6 +13,31 @@ import amalgamate_utils as am
sys.path.insert(0, f"{projdir}/ext/c4core/tools")
import amalgamate as am_c4core
class Event(Enum):
tree = "tree"
testsuite = "testsuite"
ints = "ints"
ints_utils = "ints_utils"
all = "all"
none = "none"
def __str__(self):
return self.value
event_doc = {
Event.tree: """(the default) enable the normal ryml event handler
to create the tree, and additionally the Tree, Node, parser and
emitter utilities; if this is not enabled, none of these
components will be included in the amalgamated file""",
Event.testsuite: "enable the (extra) YAML test suite event handler",
Event.ints: "enable the (extra) integer-based event handler",
Event.ints_utils: "enable the (extra) integer-based event handler utils",
Event.all: "enable all event handlers",
Event.none: "disable all event handlers",
}
ryml_defmacro = "RYML_SINGLE_HDR_DEFINE_NOW"
c4core_defmacro = "C4CORE_SINGLE_HDR_DEFINE_NOW"
exports_def_code = f""" // shared library: export when defining
@@ -42,7 +68,8 @@ c4core_def_code = f""" // propagate defines to c4core
def amalgamate_ryml(filename: str,
with_c4core: bool,
with_fastfloat: bool,
with_stl: bool):
with_stl: bool,
events: List[Event]):
c4core_amalgamated = ""
if with_c4core:
c4core_amalgamated = "src/c4/c4core_all.hpp"
@@ -66,11 +93,11 @@ INSTRUCTIONS:
`_RYML_SINGLE_HEADER_AMALGAMATED_HPP_`, ie like this:
```
#ifndef _RYML_SINGLE_HEADER_AMALGAMATED_HPP_
#include <ryml_all.hpp>
#include <header_file_name.hpp>
#endif
```
- In one (and only one) of your project source files, #define
- In one -- and only one -- of your project source files, #define
{ryml_defmacro} and then include this header. This will enable
the function and class definitions in the header file.
@@ -79,6 +106,13 @@ INSTRUCTIONS:
symbol export/import.
"""
def has_evt(*which):
if Event.all in events:
return True
for e in which:
if e in events:
return True
return False
srcfiles = [
am.cmttext(ryml_preamble),
am.cmtfile("LICENSE.txt"),
@@ -91,40 +125,49 @@ INSTRUCTIONS:
"src/c4/yml/common.hpp",
"src/c4/yml/node_type.hpp",
"src/c4/yml/tag.hpp",
"src/c4/yml/tree.hpp",
"src/c4/yml/node.hpp",
"src/c4/yml/writer.hpp",
"src/c4/yml/detail/parser_dbg.hpp",
am.injcode("#define C4_YML_EMIT_DEF_HPP_"),
"src/c4/yml/emit.hpp",
"src/c4/yml/emit.def.hpp",
am.onlyif(has_evt(Event.tree), "src/c4/yml/tree.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/node.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/writer.hpp"),
"src/c4/yml/detail/dbgprint.hpp",
am.onlyif(has_evt(Event.tree), am.injcode("#define C4_YML_EMIT_DEF_HPP_")),
am.onlyif(has_evt(Event.tree), "src/c4/yml/emit.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/emit.def.hpp"),
"src/c4/yml/detail/stack.hpp",
"src/c4/yml/filter_processor.hpp",
"src/c4/yml/parser_state.hpp",
"src/c4/yml/event_handler_stack.hpp",
"src/c4/yml/event_handler_tree.hpp",
am.onlyif(has_evt(Event.tree), "src/c4/yml/event_handler_tree.hpp"),
am.onlyif(has_evt(Event.ints), "src_extra/c4/yml/extra/event_handler_ints.hpp"),
am.onlyif(has_evt(Event.ints_utils), "src_extra/c4/yml/extra/event_handler_ints_utils.hpp"),
am.onlyif(has_evt(Event.testsuite), "src_extra/c4/yml/extra/string.hpp"),
am.onlyif(has_evt(Event.testsuite), "src_extra/c4/yml/extra/event_handler_testsuite.hpp"),
am.onlyif(has_evt(Event.ints_utils, Event.testsuite), "src_extra/c4/yml/extra/scalar.hpp"),
"src/c4/yml/parse_engine.hpp",
"src/c4/yml/preprocess.hpp",
"src/c4/yml/reference_resolver.hpp",
"src/c4/yml/parse.hpp",
am.onlyif(with_stl, "src/c4/yml/std/map.hpp"),
am.onlyif(with_stl, "src/c4/yml/std/string.hpp"),
am.onlyif(with_stl, "src/c4/yml/std/vector.hpp"),
am.onlyif(with_stl, "src/c4/yml/std/std.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/reference_resolver.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/parse.hpp"),
am.onlyif(with_stl and has_evt(Event.tree), "src/c4/yml/std/map.hpp"),
am.onlyif(with_stl and has_evt(Event.tree), "src/c4/yml/std/string.hpp"),
am.onlyif(with_stl and has_evt(Event.tree), "src/c4/yml/std/vector.hpp"),
am.onlyif(with_stl and has_evt(Event.tree), "src/c4/yml/std/std.hpp"),
"src/c4/yml/version.cpp",
"src/c4/yml/common.cpp",
"src/c4/yml/node_type.cpp",
"src/c4/yml/tag.cpp",
"src/c4/yml/tree.cpp",
"src/c4/yml/parse_engine.def.hpp",
"src/c4/yml/reference_resolver.cpp",
"src/c4/yml/parse.cpp",
"src/c4/yml/node.cpp",
am.onlyif(has_evt(Event.tree), "src/c4/yml/tree.cpp"),
am.onlyif(has_evt(Event.ints), "src_extra/c4/yml/extra/event_handler_ints.cpp"),
am.onlyif(has_evt(Event.ints_utils, Event.testsuite), "src_extra/c4/yml/extra/scalar.cpp"),
am.onlyif(has_evt(Event.ints_utils), "src_extra/c4/yml/extra/event_handler_ints_utils.cpp"),
am.onlyif(has_evt(Event.testsuite), "src_extra/c4/yml/extra/event_handler_testsuite.cpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/reference_resolver.cpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/parse.cpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/node.cpp"),
"src/c4/yml/preprocess.cpp",
"src/c4/yml/detail/checks.hpp",
"src/c4/yml/detail/print.hpp",
"src/c4/yml/yml.hpp",
"src/ryml.hpp",
am.onlyif(has_evt(Event.tree), "src/c4/yml/detail/checks.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/detail/print.hpp"),
am.onlyif(has_evt(Event.tree), "src/c4/yml/yml.hpp"),
am.onlyif(has_evt(Event.tree), "src/ryml.hpp"),
]
result = am.catfiles(srcfiles,
projdir,
@@ -143,14 +186,25 @@ INSTRUCTIONS:
def mkparser():
return am.mkparser(c4core=(True, "amalgamate c4core together with ryml"),
fastfloat=(True, "enable fastfloat library"),
stl=(True, "enable stl interop"))
p = am.mkparser(
c4core=(True, "amalgamate c4core together with ryml"),
fastfloat=(True, "enable fastfloat library"),
stl=(True, "enable stl interop")
)
default = [str(Event.tree)]
evtdoc = '. '.join([f"'{e}': {event_doc[e]}" for e in Event])
defaultdoc = ','.join([str(e) for e in default])
p.add_argument('-e', '--events', type=str, default=default, choices=[str(e) for e in Event], nargs="+",
help=f"""Specify which event handlers to include. Possible
values are: {evtdoc}. The default is {defaultdoc}.""")
return p
if __name__ == "__main__":
args = mkparser().parse_args()
args.events = [Event(e) for e in args.events] # is there a better way to do this?
amalgamate_ryml(filename=args.output,
with_c4core=args.c4core,
with_fastfloat=args.fastfloat,
with_stl=args.stl)
with_stl=args.stl,
events=args.events)

View File

@@ -6,10 +6,17 @@
#include <c4/yml/event_handler_tree.hpp>
#include <c4/yml/parse_engine.def.hpp>
#endif
#include <test_suite/test_suite_events.hpp>
#include <test_suite/test_suite_event_handler.hpp>
#include <c4/yml/extra/string.hpp>
#include <c4/yml/extra/scalar.hpp>
#include <c4/yml/extra/event_handler_ints.hpp>
#include <c4/yml/extra/event_handler_testsuite.hpp>
#include <c4/yml/extra/ints_utils.hpp>
#include <c4/yml/extra/ints_to_testsuite.hpp>
#include <testsuite/testsuite_events.hpp>
#include <c4/fs/fs.hpp>
#include <cstdio>
#include <chrono>
#ifdef C4_EXCEPTIONS
#include <stdexcept>
@@ -19,80 +26,225 @@ std::jmp_buf jmp_env = {};
c4::csubstr jmp_msg = {};
#endif
C4_SUPPRESS_WARNING_GCC("-Wold-style-cast")
//-----------------------------------------------------------------------------
const char usage[] = R"(usage:
ryml-yaml-events [-s|-t] [-] # read from stdin (default)
ryml-yaml-events [-s|-t] <file> # read from file
The option can be one of the following:
-s emit events from source: parse the YAML source,
and directly emit events during the parse (ie, no
ryml tree is created). This is the default behavior
when the option is omitted.
-t events from tree: parse the YAML source, creating a
ryml tree. Once the tree is completely created, emit
the events from the created tree.
When the option is omitted, -s is assumed.
EXAMPLES:
$ ryml-yaml-events # emit events direct from stdin
$ ryml-yaml-events - # emit events direct from stdin
$ ryml-yaml-events -s - # emit events direct from stdin
$ ryml-yaml-events -t # parse stdin to tree, emit events from created tree
$ ryml-yaml-events -t - # parse stdin to tree, emit events from created tree
$ ryml-yaml-events <file> # emit events direct from file
$ ryml-yaml-events - <file> # emit events direct from file
$ ryml-yaml-events -s <file> # emit events direct from file
$ ryml-yaml-events -t <file> # parse file to tree, emit events from created tree
)";
using namespace c4;
using namespace c4::yml;
enum class evts_type
{
testsuite_src,
testsuite_ints,
testsuite_tree,
ryml_ints,
};
struct Args
{
csubstr filename = "-";
bool events_from_tree = false;
static bool parse(Args *args, int argc, const char *argv[]);
evts_type evts = evts_type::testsuite_src;
int ints_size = -1; // estimate by default
bool ints_size_force = false; // do not force the estimated size
static bool parse(Args *args, int argc, const char *argv[], int *errcode);
};
const char usage[] = R"(usage:
ryml-yaml-events <command> <options> [-] # read from stdin (default)
ryml-yaml-events <command> <options> <file> # read from file
The command must be one of the following:
testsuite_src,ts_src,tss
emit test suite events directly from source: parse the YAML
source, and directly emit events during the parse (ie, no
ryml tree is created). This is the default behavior when the
option is omitted.
testsuite_tree,ts_tree,tst
emit test suite events from tree: parse the YAML source,
creating a ryml tree. Once the tree is completely created,
emit the test suite events by iterating over the nodes of the
created tree.
testsuite_ints,ts_ints,tsi
emit test suite events from the ryml int events handler:
parse the YAML source to a container of ryml int events. Once
this is completed, emit the corresponding test suite events.
ryml_ints,ri
emit ryml int events: parse the YAML source to a container of
ryml int events. Once this is completed, print those same int
events.
The following options influence the behavior of the program:
--timings,--timing,-t
print task timings and size information (to stderr)
The following options influence the behavior of testsuite_ints and ryml_ints:
--ints-size <int-number>,-is <int-number>
when using int events, set the int event buffer size from this
value. use a negative value to force a conservative estimation
from a first run over the YAML source, and then multiply the
estimation by the symmetrical of that value. For example, -2
will result in 2*estimation. Default is -1.
--ints-size-force,-isf
when using int events, force the initial int event buffer size
to prevail: if this size is not large enough to accomodate the
actual number of events required from the YAML source, exit
with a nonzero error code. This is in contrast to the default
behavior, which consists of expanding the buffer as needed,
which requires two parses and two string copies of the
original source buffer.
EXAMPLES:
$ ryml-yaml-events ts_src # parse stdin to test suite events, then print the events
$ ryml-yaml-events ts_src - # parse stdin to test suite events, then print the events
$ ryml-yaml-events ts_src <file> # parse file to test suite events, then print the events
$ ryml-yaml-events ts_tree # parse stdin to ryml tree, emit test suite events from created tree
$ ryml-yaml-events ts_tree - # parse stdin to ryml tree, emit test suite events from created tree
$ ryml-yaml-events ts_tree <file> # parse file to ryml tree, emit test suite events from created tree
$ ryml-yaml-events ts_ints # parse stdin to ryml int events, emit test suite events from ryml int events
$ ryml-yaml-events ts_ints - # parse stdin to ryml int events, emit test suite events from ryml int events
$ ryml-yaml-events ts_ints <file> # parse file to ryml int events, emit test suite events from ryml int events
$ ryml-yaml-events ryml_ints # parse stdin to ryml int events, emit ryml int events
$ ryml-yaml-events ryml_ints - # parse stdin to ryml int events, emit ryml int events
$ ryml-yaml-events ryml_ints <file> # parse file to ryml int events, emit ryml int events
)";
//-----------------------------------------------------------------------------
using IntEvents = std::vector<extra::ievt::DataType>;
std::string load_file(csubstr filename);
std::string emit_events_from_tree(csubstr filename, substr filecontents);
std::string emit_events_direct(csubstr filename, substr filecontents);
extra::string emit_testsuite_events(csubstr filename, substr filecontents);
std::string emit_testsuite_events_from_tree(csubstr filename, substr filecontents);
std::string emit_testsuite_events_from_ints(csubstr filename, substr filecontents, IntEvents &evts, bool fail_size);
void emit_ints_events(csubstr filename, substr filecontents, IntEvents &evts, bool fail_size);
int estimate_ints_size(csubstr filecontents, int size);
Callbacks create_custom_callbacks();
bool timing_enabled = false;
double src_size = 0;
namespace stdc = std::chrono;
struct stopwatch
{
using clock_type = stdc::steady_clock;
const char *name;
clock_type::time_point start;
stopwatch(const char *name_)
{
if(!timing_enabled) return;
name = name_;
stack.emplace_back(this);
start = clock_type::now();
}
~stopwatch()
{
if(!timing_enabled) return;
stdc::duration<double, std::milli> delta = clock_type::now() - start;
for(stopwatch const* sw : stack)
fprintf(stderr, "%s:", sw->name);
fprintf(stderr, " %.6fms (%.3fMB/s)\n", delta.count(), src_size / delta.count() * 1.e-3);
stack.resize(stack.size()-1);
}
static std::vector<stopwatch*> stack;
};
std::vector<stopwatch*> stopwatch::stack;
#define STOPWATCH(name) stopwatch C4_XCAT(timer, __LINE__){name}
//-----------------------------------------------------------------------------
int main(int argc, const char *argv[])
{
Args args = {};
if(!Args::parse(&args, argc, argv))
return 1;
{
int errcode = 0;
if(!Args::parse(&args, argc, argv, &errcode))
return errcode;
}
set_callbacks(create_custom_callbacks());
C4_IF_EXCEPTIONS_(try, if(setjmp(jmp_env) == 0))
{
std::string src = load_file(args.filename);
const std::string events = args.events_from_tree ?
emit_events_from_tree(args.filename, to_substr(src))
:
emit_events_direct(args.filename, to_substr(src));
std::fwrite(events.data(), 1, events.size(), stdout);
std::string src;
{
STOPWATCH("load_file");
src = load_file(args.filename);
src_size = (double)src.size();
if(timing_enabled) fprintf(stderr, "src_size=%zuB\n", src.size());
}
STOPWATCH("process");
switch(args.evts)
{
case evts_type::testsuite_src:
{
extra::string evts;
{
STOPWATCH("testsuite_src");
evts = emit_testsuite_events(args.filename, to_substr(src));
}
{
STOPWATCH("print");
std::fwrite(evts.data(), 1, evts.size(), stdout);
}
break;
}
case evts_type::testsuite_tree:
{
std::string evts;
{
STOPWATCH("testsuite_tree");
evts = emit_testsuite_events_from_tree(args.filename, to_substr(src));
}
{
STOPWATCH("print");
std::fwrite(evts.data(), 1, evts.size(), stdout);
}
break;
}
case evts_type::testsuite_ints:
{
substr ssrc = to_substr(src);
int estimated_size = estimate_ints_size(ssrc, args.ints_size);
IntEvents int_evts((size_t)estimated_size);
std::string ts_evts;
{
STOPWATCH("testsuite_ints");
ts_evts = emit_testsuite_events_from_ints(args.filename, to_substr(src), int_evts, args.ints_size_force);
}
{
STOPWATCH("print");
std::fwrite(ts_evts.data(), 1, ts_evts.size(), stdout);
}
break;
}
case evts_type::ryml_ints:
{
substr ssrc = to_substr(src);
int estimated_size = estimate_ints_size(ssrc, args.ints_size);
IntEvents int_evts((size_t)estimated_size);
{
STOPWATCH("ryml_ints");
emit_ints_events(args.filename, to_substr(src), int_evts, args.ints_size_force);
}
break;
}
}
}
C4_IF_EXCEPTIONS_(catch(std::exception const&), else)
{
@@ -104,49 +256,206 @@ int main(int argc, const char *argv[])
//-----------------------------------------------------------------------------
std::string emit_events_from_tree(csubstr filename, substr filecontents)
std::string emit_testsuite_events_from_tree(csubstr filename, substr filecontents)
{
Tree tree(create_custom_callbacks());
tree.reserve(estimate_tree_capacity(filecontents));
parse_in_place(filename, filecontents, &tree);
return emit_events_from_tree<std::string>(tree);
{
STOPWATCH("tree_reserve");
tree.reserve(estimate_tree_capacity(filecontents));
}
{
STOPWATCH("parse");
parse_in_place(filename, filecontents, &tree);
}
{
STOPWATCH("emit_events");
std::string result = emit_events_from_tree<std::string>(tree);
return result;
}
}
std::string emit_events_direct(csubstr filename, substr filecontents)
extra::string emit_testsuite_events(csubstr filename, substr filecontents)
{
EventHandlerYamlStd::EventSink sink = {};
EventHandlerYamlStd handler(&sink, create_custom_callbacks());
ParseEngine<EventHandlerYamlStd> parser(&handler);
parser.parse_in_place_ev(filename, filecontents);
csubstr result = sink;
return std::string(result.str, result.len);
extra::EventHandlerTestSuite::EventSink sink = {};
extra::EventHandlerTestSuite handler(&sink, create_custom_callbacks());
ParseEngine<extra::EventHandlerTestSuite> parser(&handler);
{
STOPWATCH("parse");
parser.parse_in_place_ev(filename, filecontents);
}
return sink;
}
csubstr parse_events_ints(csubstr filename, substr filecontents, std::string &parsed, std::string &arena, IntEvents &evts, bool fail_size)
{
using I = extra::ievt::DataType;
using Handler = extra::EventHandlerInts;
Handler handler(create_custom_callbacks());
ParseEngine<Handler> parser(&handler);
substr src = filecontents;
if(!fail_size)
{
STOPWATCH("copy_src");
parsed.assign(filecontents.str, filecontents.len);
src = to_substr(parsed);
}
arena.resize(src.len);
handler.reset(src, to_substr(arena), evts.data(), (I)evts.size());
{
STOPWATCH("parse");
parser.parse_in_place_ev(filename, src);
}
size_t sz = (size_t)handler.required_size_events();
if(timing_enabled) fprintf(stderr, "current_size=%zu vs needed_size=%zu. arena_size=%zu\n", evts.size(), sz, arena.size());
if (!handler.fits_buffers())
{
RYML_CHECK(!fail_size);
{
STOPWATCH("resize");
evts.resize(sz);
arena.resize(handler.required_size_arena());
}
{
STOPWATCH("redo_copy_src");
parsed.assign(filecontents.str, filecontents.len);
src = to_substr(parsed);
}
handler.reset(src, to_substr(arena), evts.data(), (I)evts.size());
{
STOPWATCH("redo_parse");
parser.parse_in_place_ev(filename, src);
}
RYML_CHECK((size_t)handler.m_evt_pos == sz);
}
evts.resize(sz);
return src;
}
std::string emit_testsuite_events_from_ints(csubstr filename, substr filecontents, IntEvents &evts, bool fail_size)
{
using I = extra::ievt::DataType;
std::string buf;
std::string arena;
csubstr parsed;
{
STOPWATCH("events");
parsed = parse_events_ints(filename, filecontents, buf, arena, evts, fail_size);
}
std::string result;
{
STOPWATCH("emit");
extra::events_ints_to_testsuite(parsed, to_substr(arena), evts.data(), (I)evts.size(), &result);
}
return result;
}
void emit_ints_events(csubstr filename, substr filecontents, IntEvents &evts, bool fail_size)
{
using I = extra::ievt::DataType;
std::string buf;
std::string arena;
csubstr parsed;
{
STOPWATCH("events");
parsed = parse_events_ints(filename, filecontents, buf, arena, evts, fail_size);
}
{
STOPWATCH("emit");
extra::events_ints_print(parsed, to_substr(arena), evts.data(), (I)evts.size());
}
}
int estimate_ints_size(csubstr filecontents, int size)
{
if(size < 0)
{
STOPWATCH("estimate_size");
int est = extra::estimate_events_ints_size(filecontents);
if(timing_enabled) fprintf(stderr, "estimated_size=%d*%d=%d\n", -size, est, -size * est);
size = -size * est;
}
return size;
}
//-----------------------------------------------------------------------------
bool Args::parse(Args *args, int argc, const char *argv[])
// return true if the program should continue (eg -h should exit)
bool Args::parse(Args *args, int argc, const char *argv[], int *errcode)
{
if(argc > 3)
{
*errcode = 0;
auto argerr = [&](const char *msg){
std::printf(usage);
std::printf("ERROR: %s\n", msg);
*errcode = 1;
return false;
}
};
// set defaults
*args = {};
if(argc == 3)
// parse the command argument
if(argc < 2)
return argerr("must provide a command"); // LCOV_EXCL_LINE
bool has_cmd = false;
{
args->events_from_tree = (to_csubstr(argv[1]) == "-t");
args->filename = to_csubstr(argv[2]);
csubstr s = to_csubstr(argv[1]);
if(s == "testsuite_src" || s == "ts_src" || s == "tss")
{
args->evts = evts_type::testsuite_src;
has_cmd = true;
}
else if(s == "testsuite_tree" || s == "ts_tree" || s == "tst")
{
args->evts = evts_type::testsuite_tree;
has_cmd = true;
}
else if(s == "testsuite_ints" || s == "ts_ints" || s == "tsi")
{
args->evts = evts_type::testsuite_ints;
has_cmd = true;
}
else if(s == "ryml_ints" || s == "ri")
{
args->evts = evts_type::ryml_ints;
has_cmd = true;
}
else if(s == "--help" || s == "-h")
{
std::printf(usage);
return false;
}
}
else if(argc == 2)
if(!has_cmd)
return argerr("unknown command");
// parse other args
int i = 2; // cmd is mandatory at i=1, so start after that at i=2
for(; i < argc; ++i)
{
csubstr a = to_csubstr(argv[1]);
if(a == "-t")
args->events_from_tree = true;
else if(a == "-s")
args->events_from_tree = false;
csubstr arg = to_csubstr(argv[i]);
if(arg == "--help" || arg == "-h")
{
std::printf(usage);
return false;
}
else if(arg == "--timings" || arg == "--timing" || arg == "-t")
{
timing_enabled = true;
}
else if(arg == "--ints-size-force" || arg == "-isf")
{
args->ints_size_force = true;
}
else if(arg == "--ints-size" || arg == "-is")
{
if(i + 1 >= argc)
return argerr("ints-size value not given"); // LCOV_EXCL_LINE
else if(!atoi(to_csubstr(argv[i+1]), &args->ints_size))
return argerr("ints-size value fails to parse"); // LCOV_EXCL_LINE
++i; // shift 1
}
else
args->filename = a;
{
args->filename = arg;
}
}
return true;
}
@@ -154,19 +463,16 @@ bool Args::parse(Args *args, int argc, const char *argv[])
std::string load_file(csubstr filename)
{
if(filename == "-") // read from stdin
{
{ // LCOV_EXCL_START
std::string buf;
buf.reserve(128);
for(int c = std::getchar(); c != EOF; c = std::getchar())
{
buf.push_back(static_cast<char>(c));
if(buf.size() == buf.capacity())
buf.reserve(2u * (buf.capacity() >= 128u ? buf.capacity() : 128u));
}
return buf;
return buf; // LCOV_EXCL_STOP
}
if(!fs::path_exists(filename.str))
else if(!fs::path_exists(filename.str))
{
std::fprintf(stderr, "cannot find file: %s (cwd=%s)\n", filename.str, fs::cwd<std::string>().c_str());
std::fprintf(stderr, "%s: file not found (cwd=%s)\n", filename.str, fs::cwd<std::string>().c_str());
error("file not found");
}
return fs::file_get_contents<std::string>(filename.str);
@@ -204,4 +510,3 @@ Callbacks create_custom_callbacks()
};
return callbacks;
}