• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

biojppm / rapidyaml / 14071541066

25 Mar 2025 10:45PM UTC coverage: 97.524% (-0.06%) from 97.586%
14071541066

Pull #508

github

web-flow
Merge d27170bc2 into d3132a25e
Pull Request #508: fix build with cmake 4

11539 of 11832 relevant lines covered (97.52%)

764866.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.71
/tools/parse_emit.cpp
1
#ifdef RYML_SINGLE_HEADER
2
#include <ryml_all.hpp>
3
#else
4
#include <c4/yml/std/std.hpp>
5
#include <c4/yml/parse.hpp>
6
#include <c4/yml/emit.hpp>
7
#include <c4/yml/common.hpp>
8
#endif
9
#include <c4/fs/fs.hpp>
10

11
#include <cstdio>
12
#include <chrono>
13

14
#ifdef C4_EXCEPTIONS
15
#include <stdexcept>
16
#else
17
#include <csetjmp>
18
std::jmp_buf jmp_env = {};
19
c4::csubstr jmp_msg = {};
20
#endif
21

22

23
using namespace c4;
24

25

26
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
27
C4_SUPPRESS_WARNING_GCC("-Wuseless-cast")
28

29

30
bool quiet = false;
31
bool emit_as_json = false;
32
bool timed_sections = false;
33
bool emit_to_string = false;
34

35

36
//-----------------------------------------------------------------------------
37

38
struct timed_section
39
{
40
    using myclock = std::chrono::steady_clock;
41
    using msecs = std::chrono::duration<double, std::milli>;
42

43
    csubstr name;
44
    myclock::time_point start;
45

46
    msecs since() const { return myclock::now() - start; }
×
47
    timed_section(csubstr n) : name(n), start(myclock::now()) {}
56✔
48
    ~timed_section()
56✔
49
    {
50
        if(timed_sections)
56✔
51
        {
52
            fprintf(stderr, "%.6fms: %.*s\n", since().count(), (int)name.len, name.str);
×
53
            fflush(stderr);
×
54
        }
55
    }
56✔
56
};
57

58
#define TS(name) timed_section C4_XCAT(__, C4_XCAT(name, __LINE__))(#name)
59

60
// LCOV_EXCL_START
61

62
constexpr const char *usage = R"(usage:
63

64
   %s <options> <path/to/file.yaml>
65

66
Parse yaml from file (or stdin when file is `-`) and emit to stdout.
67

68
Options:
69

70
  -q,--quiet    do not emit (default: emit yaml)
71
  -d,--debug    print rapidyaml tree
72
  -j,--json     emit json instead of yaml (default: emit yaml)
73
  -s,--string   emit to string before dumping to stdout.
74
                otherwise, emit directly to stdout
75
  -t,--timed    time sections (print timings to stderr)
76

77
)";
78

79
csubstr parse_args(int argc, const char *argv[])
80
{
81
    if(argc < 2)
82
    {
83
        printf(usage, argv[0]);
84
        yml::error("unknown argument");
85
    }
86
    csubstr file = to_csubstr(argv[argc - 1]);
87
    for(int i = 1; i+1 < argc; ++i)
88
    {
89
        csubstr arg = to_csubstr(argv[i]);
90
        if(arg == "-q" || arg == "--quiet")
91
            quiet = true;
92
        else if(arg == "-t" || arg == "--timed")
93
            timed_sections = true;
94
        else if(arg == "-s" || arg == "--string")
95
            emit_to_string = true;
96
        else if(arg == "-j" || arg == "--json")
97
            emit_as_json = true;
98
        else
99
        {
100
            printf(usage, argv[0]);
101
            yml::error("unknown argument");
102
        }
103
    }
104
    return file;
105
}
106

107
void load_file(csubstr filename, std::string *buf)
108
{
109
    buf->clear();
110
    if(filename == "-") // read from stdin
111
    {
112
        for(int c = std::getchar(); c != EOF; c = std::getchar())
113
        {
114
            buf->push_back((char)c);
115
            if(buf->size() == buf->capacity())
116
                buf->reserve(2u * (buf->capacity() >= 128u ? buf->capacity() : 128u));
117
        }
118
    }
119
    else
120
    {
121
        if(!fs::path_exists(filename.str))
122
        {
123
            std::fprintf(stderr, "cannot find file: %s (cwd=%s)\n", filename.str, fs::cwd<std::string>().c_str());
124
            yml::error("file not found");
125
        }
126
        fs::file_get_contents<std::string>(filename.str, buf);
127
    }
128
}
129

130
void emit_json_docs(yml::Tree const& tree, std::string *dst=nullptr)
131
{
132
    auto emitnode = [&](yml::ConstNodeRef node){
133
        if(dst)
134
        {
135
            emitrs_json(node, dst, /*append*/true);
136
            *dst += '\n';
137
        }
138
        else
139
        {
140
            emit_json(node, stdout);
141
        }
142
    };
143
    yml::ConstNodeRef root = tree.rootref();
144
    if(!root.is_stream())
145
        emitnode(root);
146
    else
147
        for(yml::ConstNodeRef doc : root.children())
148
            emitnode(doc);
149
}
150

151
void report_error(const char* msg, size_t length, yml::Location loc, FILE *f)
152
{
153
    if(!loc.name.empty())
154
    {
155
        fwrite(loc.name.str, 1, loc.name.len, f);
156
        fputc(':', f);
157
    }
158
    fprintf(f, "%zu:", loc.line);
159
    if(loc.col)
160
        fprintf(f, "%zu:", loc.col);
161
    if(loc.offset)
162
        fprintf(f, " (%zuB):", loc.offset);
163
    fputc(' ', f);
164
    fprintf(f, "%.*s\n", static_cast<int>(length), msg);
165
    fflush(f);
166
}
167

168
yml::Callbacks create_custom_callbacks()
169
{
170
    yml::Callbacks callbacks = {};
171
    callbacks.m_error = [](const char *msg, size_t msg_len, yml::Location location, void *)
172
    {
173
        report_error(msg, msg_len, location, stderr);
174
        C4_IF_EXCEPTIONS(
175
            throw std::runtime_error({msg, msg_len});
176
            ,
177
            jmp_msg.assign(msg, msg_len);
178
            std::longjmp(jmp_env, 1);
179
        );
180
    };
181
    return callbacks;
182
}
183

184

185
//-----------------------------------------------------------------------------
186
//-----------------------------------------------------------------------------
187
//-----------------------------------------------------------------------------
188

189
void process_file(csubstr file)
190
{
191
    TS(objects);
192
    std::string contents;
193
    yml::Tree tree(yml::get_callbacks());
194
    {
195
        TS(read_file);
196
        load_file(file, &contents);
197
    }
198
    {
199
        TS(tree_reserve);
200
        yml::id_type cap;
201
        {
202
            TS(estimate_capacity);
203
            cap = yml::estimate_tree_capacity(to_csubstr(contents));
204
        }
205
        fprintf(stderr, "reserving capacity=%zu\n", (size_t)cap);
206
        tree.reserve(cap);
207
    }
208
    {
209
        TS(parse_yml);
210
        yml::parse_in_place(file, to_substr(contents), &tree);
211
    }
212
    if(emit_as_json)
213
    {
214
        TS(resolve_refs);
215
        tree.resolve();
216
    }
217
    if(emit_to_string)
218
    {
219
        std::string output;
220
        {
221
            TS(emit_to_buffer);
222
            output.resize(contents.size()); // resize, not just reserve
223
            if(!emit_as_json)
224
                yml::emitrs_yaml(tree, &output);
225
            else
226
                emit_json_docs(tree, &output);
227
        }
228
        if(!quiet)
229
        {
230
            TS(print_stdout);
231
            fwrite(output.data(), 1, output.size(), stdout);
232
        }
233
    }
234
    else if(!quiet)
235
    {
236
        TS(emit_to_stdout);
237
        if(!emit_as_json)
238
            yml::emit_yaml(tree);
239
        else
240
            emit_json_docs(tree);
241
    }
242
}
243
// LCOV_EXCL_STOP
244

245
int main(int argc, const char *argv[])
8✔
246
{
247
    TS(TOTAL);
8✔
248
    set_callbacks(create_custom_callbacks());
8✔
249
    C4_IF_EXCEPTIONS_(try, if(setjmp(jmp_env) == 0))
250
    {
251
        csubstr file = parse_args(argc, argv);
8✔
252
        process_file(file);
8✔
253
    }
254
    C4_IF_EXCEPTIONS_(catch(std::exception const&), else)
×
255
    {
256
        return 1;
×
257
    }
×
258
    return 0;
8✔
259
}
8✔
260

261
C4_SUPPRESS_WARNING_GCC_CLANG_POP
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc