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

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

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

64.89
/libs/core/ini/src/ini.cpp
1
//  Copyright (c) 2005-2007 Andre Merzky
2
//  Copyright (c) 2005-2025 Hartmut Kaiser
3
//  Copyright (c)      2011 Bryce Lelbach
4
//
5
//  SPDX-License-Identifier: BSL-1.0
6
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
7
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8

9
#include <hpx/config.hpp>
10

11
// System Header Files
12
#include <cerrno>
13
#include <cstddef>
14
#include <cstdint>
15
#include <cstdio>
16
#include <cstdlib>
17
#include <cstring>
18
#include <fstream>
19
#include <iostream>
20
#include <list>
21
#include <mutex>
22
#include <regex>
23
#include <string>
24
#include <type_traits>
25
#include <utility>
26
#include <vector>
27

28
#include <hpx/assert.hpp>
29
#include <hpx/ini/ini.hpp>
30
#include <hpx/modules/errors.hpp>
31
#include <hpx/modules/serialization.hpp>
32
#include <hpx/modules/string_util.hpp>
33
#include <hpx/modules/thread_support.hpp>
34

35
#ifdef __APPLE__
36
#include <crt_externs.h>
37
#define environ (*_NSGetEnviron())
38
#elif !defined(HPX_WINDOWS)
39
extern char** environ;
40
#endif
41

42
///////////////////////////////////////////////////////////////////////////////
43
namespace hpx::util {
44

45
    ///////////////////////////////////////////////////////////////////////////////
46
    // example ini line: line # comment
47
    inline constexpr char const pattern_comment[] = "^([^#]*)(#.*)$";
48
    ///////////////////////////////////////////////////////////////////////////////
49

50
    namespace detail {
51

52
        ///////////////////////////////////////////////////////////////////////////
53
        inline std::string trim_whitespace(std::string const& s)
54
        {
55
            typedef std::string::size_type size_type;
142,577✔
56

57
            size_type const first = s.find_first_not_of(" \t\r\n");
58
            if (std::string::npos == first)
59
                return (std::string());
60

142,577✔
61
            size_type const last = s.find_last_not_of(" \t\r\n");
62
            return s.substr(first, last - first + 1);
63
        }
64

141,905✔
65
        // MSVC: using std::string::replace triggers ASAN reports
66
        std::string replace_substr(std::string const& str,
67
            std::size_t start_pos, std::size_t oldlen, char const* newstr)
68
        {
17,095✔
69
            std::string result(str.substr(0, start_pos));
70
            result += newstr;
71
            result += str.substr(start_pos + oldlen);
17,095✔
72
            return result;
73
        }
17,095✔
74

17,095✔
75
        std::string replace_substr(std::string const& str,
76
            std::size_t start_pos, std::size_t oldlen,
77
            std::string const& newstr)
×
78
        {
79
            return replace_substr(str, start_pos, oldlen, newstr.c_str());
80
        }
81
    }    // namespace detail
16,711✔
82

83
    ///////////////////////////////////////////////////////////////////////////////
84
    section::section() noexcept
85
      : root_(this_())
86
    {
28,246✔
87
    }
28,246✔
88

89
    section::section(std::string const& filename, section* root)
28,246✔
90
      : root_(nullptr != root ? root : this_())
91
      , name_(filename)
×
92
    {
×
93
        read(filename);
×
94
    }
95

×
96
    section::section(section const& in)
×
97
      : root_(this_())
98
      , name_(in.get_name())
22,272✔
99
      , parent_name_(in.get_parent_name())
22,272✔
100
    {
101
        entry_map const& e = in.get_entries();
102
        auto const end = e.end();
103
        for (auto i = e.begin(); i != end; ++i)
104
            add_entry(i->first, i->second);
105

143,600✔
106
        section_map s = in.get_sections();
121,328✔
107
        auto const send = s.end();
108
        for (auto si = s.begin(); si != send; ++si)
22,272✔
109
            add_section(si->first, si->second, get_root());
110
    }
33,472✔
111

11,200✔
112
    section& section::operator=(section const& rhs)
22,272✔
113
    {
114
        if (this != &rhs)
96✔
115
        {
116
            std::unique_lock<mutex_type> l(mtx_);
96✔
117

118
            root_ = this;
96✔
119
            parent_name_ = rhs.get_parent_name();
120
            name_ = rhs.get_name();
96✔
121

192✔
122
            entry_map const& e = rhs.get_entries();
192✔
123
            auto const end = e.end();
124
            for (auto i = e.begin(); i != end; ++i)
125
                add_entry(l, i->first, i->first, i->second);
126

288✔
127
            section_map s = rhs.get_sections();
192✔
128
            auto const send = s.end();
129
            for (auto si = s.begin(); si != send; ++si)
130
                add_section(l, si->first, si->second, get_root());
131
        }
288✔
132
        return *this;
192✔
133
    }
134

96✔
135
    section& section::clone_from(section const& rhs, section* root)
136
    {
137
        if (this != &rhs)
25,083✔
138
        {
139
            std::unique_lock<mutex_type> l(mtx_);
25,083✔
140

141
            root_ = root ? root : this;
25,083✔
142
            parent_name_ = rhs.get_parent_name();
143
            name_ = rhs.get_name();
25,083✔
144

50,166✔
145
            entry_map const& e = rhs.get_entries();
50,166✔
146
            auto const end = e.end();
147
            for (auto i = e.begin(); i != end; ++i)
148
                add_entry(l, i->first, i->first, i->second);
149

146,411✔
150
            section_map s = rhs.get_sections();
121,328✔
151
            auto const send = s.end();
152
            for (auto si = s.begin(); si != send; ++si)
153
                add_section(l, si->first, si->second, get_root());
154
        }
35,803✔
155
        return *this;
10,720✔
156
    }
157

25,083✔
158
    void section::read(std::string const& filename)
159
    {
160
#if defined(__AIX__) && defined(__GNUC__)
×
161
        // NEVER ask why... seems to be some weird stdlib initialization problem
162
        // If you don't call getline() here the while(getline...) loop below will
163
        // crash with a bad_cast exception. Stupid AIX...
164
        std::string l1;
165
        std::ifstream i1;
166
        i1.open(filename.c_str(), std::ios::in);
167
        std::getline(i1, l1);
168
        i1.close();
169
#endif
170

171
        // build ini - open file and parse each line
172
        std::ifstream input(filename.c_str(), std::ios::in);
173
        if (!input.is_open())
174
            line_msg("Cannot open file: ", filename);
×
175

×
176
        // read file
×
177
        std::string line;
178
        std::vector<std::string> lines;
179
        while (std::getline(input, line))
180
            lines.push_back(line);
×
181

×
182
        // parse file
×
183
        parse(filename, lines, false);
184
    }
185

×
186
    bool force_entry(std::string& str)
×
187
    {
188
        std::string::size_type const p = str.find_last_of('!');
54,055✔
189
        if (p != std::string::npos &&
190
            str.find_first_not_of(" \t", p + 1) == std::string::npos)
191
        {
54,055✔
192
            str = str.substr(0, p);    // remove forcing modifier ('!')
1,457✔
193
            return true;
194
        }
1,457✔
195
        return false;
1,457✔
196
    }
197

198
    // parse file
199
    void section::parse(std::string const& sourcename,
200
        std::vector<std::string> const& lines, bool verify_existing,
201
        bool weed_out_comments, bool replace_existing)
956✔
202
    {
203
        int linenum = 0;
204
        section* current = this;
205

206
        std::regex regex_comment(pattern_comment, std::regex_constants::icase);
207

208
        auto const end = lines.end();
956✔
209
        for (auto it = lines.begin(); it != end; ++it)
210
        {
211
            ++linenum;
64,799✔
212

213
            // remove trailing new lines and white spaces
63,843✔
214
            std::string line(detail::trim_whitespace(*it));
215

216
            // skip if empty line
63,843✔
217
            if (line.empty())
218
                continue;
219

63,843✔
220
            // weed out comments
480✔
221
            if (weed_out_comments)
222
            {
223
                std::smatch what_comment;
63,363✔
224
                if (std::regex_match(line, what_comment, regex_comment))
225
                {
226
                    HPX_ASSERT(3 == what_comment.size());
32✔
227

228
                    line = detail::trim_whitespace(what_comment[1]);
229
                    if (line.empty())
230
                        continue;
×
231
                }
×
232
            }
233
            // no comments anymore: line is either section, key=val, or
234
            // garbage/empty
235

236
            // Check if we have a section. Example: [sec.ssec]
237
            if (line.front() == '[' && line.back() == ']')
238
            {
239
                current = this;    // start adding sections at the root
63,363✔
240

241
                // got the section name. It might be hierarchical, so split it
242
                // up, and for each elem, check if we have it. If not, create
243
                // it, and add
244
                std::string sec_name(line.substr(1, line.size() - 2));
245
                std::string::size_type pos = 0;
246
                for (std::string::size_type pos1 = sec_name.find_first_of('.');
9,308✔
247
                    std::string::npos != pos1;
248
                    pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
9,308✔
249
                {
25,204✔
250
                    current = current->add_section_if_new(
15,896✔
251
                        sec_name.substr(pos, pos1 - pos));
252
                }
15,896✔
253

31,792✔
254
                current = current->add_section_if_new(sec_name.substr(pos));
255
                continue;
256
            }
18,616✔
257

258
            // Check if we have a key=val entry...
259
            std::string::size_type assign_pos = line.find('=');
260
            if (assign_pos != std::string::npos)
261
            {
54,055✔
262
                std::string sec_key =
54,055✔
263
                    detail::trim_whitespace(line.substr(0, assign_pos));
264

265
                section* s = current;    // save the section we're in
108,110✔
266
                current = this;          // start adding sections at the root
267

268
                std::string::size_type pos = 0;
269

270
                // Check if we have a qualified key name
271
                // Example: hpx.commandline.allow_unknown
272
                for (std::string::size_type dot_pos =
273
                         sec_key.find_first_of('.');
274
                    std::string::npos != dot_pos;
54,055✔
275
                    dot_pos = sec_key.find_first_of('.', pos = dot_pos + 1))
276
                {
58,659✔
277
                    current = current->add_section_if_new(
4,604✔
278
                        sec_key.substr(pos, dot_pos - pos));
279
                }
4,604✔
280

9,208✔
281
                // if we don't have section qualifiers, restore current...
282
                if (current == this)
283
                {
284
                    current = s;
54,055✔
285
                }
286

287
                std::string key = sec_key.substr(pos);
288

289
                // add key/val to this section
54,055✔
290
                std::unique_lock<mutex_type> l(current->mtx_);
291

292
                if (!force_entry(key) && verify_existing &&
54,055✔
293
                    !current->has_entry(l, key))
294
                {
56,041✔
295
                    line_msg("Attempt to initialize unknown entry: ",
1,986✔
296
                        sourcename, linenum, line);
297
                }
×
298

299
                if (replace_existing || !current->has_entry(l, key))
300
                {
301
                    std::string value = detail::trim_whitespace(line.substr(
54,055✔
302
                        assign_pos + 1, line.size() - assign_pos - 1));
303
                    current->add_entry(l, key, key, value);
24,679✔
304
                }
24,679✔
305

49,358✔
306
                // restore the old section
307
                current = s;
308
            }
309
            else
310
            {
311
                // Hmm, is not a section, is not an entry, is not empty - must be
312
                // an error!
313
                line_msg("Cannot parse line at: ", sourcename, linenum, line);
314
            }
315
        }
×
316
    }
317

318
    ///////////////////////////////////////////////////////////////////////////////
956✔
319
    void section::add_section(std::unique_lock<mutex_type>& /* l */,
320
        std::string const& sec_name, section& sec, section* root)
321
    {
25,083✔
322
        // setting name and root
323
        sec.name_ = sec_name;
324
        sec.parent_name_ = get_full_name();
325

25,083✔
326
        section& newsec = sections_[sec_name];
25,083✔
327
        newsec.clone_from(sec, (nullptr != root) ? root : get_root());
328
    }
25,083✔
329

25,083✔
330
    ///////////////////////////////////////////////////////////////////////////
25,083✔
331
    section* section::add_section_if_new(
332
        std::unique_lock<mutex_type>& l, std::string const& sec_name)
333
    {
30,180✔
334
        // do we know this one?
335
        if (!has_section(l, sec_name))
336
        {
337
            // no - add it!
30,180✔
338
            section sec;
339
            add_section(l, sec_name, sec, get_root());
340
        }
2,971✔
341

2,971✔
342
        return get_section(l, sec_name);
2,971✔
343
    }
344

30,180✔
345
    bool section::has_section(
346
        std::unique_lock<mutex_type>& l, std::string const& sec_name) const
347
    {
36,807✔
348
        std::string::size_type const i = sec_name.find('.');
349
        if (i != std::string::npos)
350
        {
36,807✔
351
            std::string const cor_sec_name = sec_name.substr(0, i);
36,807✔
352

353
            auto const it = sections_.find(cor_sec_name);
3,934✔
354
            if (it != sections_.end())
355
            {
356
                std::string const sub_sec_name = sec_name.substr(i + 1);
3,934✔
357
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
358
                return (*it).second.has_section(sub_sec_name);
3,934✔
359
            }
360
            return false;
3,934✔
361
        }
362
        return sections_.find(sec_name) != sections_.end();
363
    }
364

32,873✔
365
    section* section::get_section(
366
        std::unique_lock<mutex_type>& l, std::string const& sec_name)
367
    {
33,400✔
368
        std::string::size_type const i = sec_name.find('.');
369
        if (i != std::string::npos)
370
        {
33,400✔
371
            std::string const cor_sec_name = sec_name.substr(0, i);
33,400✔
372
            auto const it = sections_.find(cor_sec_name);
373
            if (it != sections_.end())
2,102✔
374
            {
375
                std::string const sub_sec_name = sec_name.substr(i + 1);
2,102✔
376
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
377
                return (*it).second.get_section(sub_sec_name);
2,102✔
378
            }
379

2,102✔
380
            std::string name(get_name());
381
            if (name.empty())
382
                name = "<root>";
383

×
384
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
385
                "section::get_section", "No such section ({}) in section: {}",
386
                sec_name, name);
×
387
        }
388

389
        auto const it = sections_.find(sec_name);
390
        if (it != sections_.end())
391
            return &((*it).second);
392

31,298✔
393
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section",
31,298✔
394
            "No such section ({}) in section: {}", sec_name, get_name());
395
    }
×
396

397
    section const* section::get_section(
398
        std::unique_lock<mutex_type>& l, std::string const& sec_name) const
399
    {
7,031✔
400
        std::string::size_type const i = sec_name.find('.');
401
        if (i != std::string::npos)
402
        {
7,031✔
403
            std::string const cor_sec_name = sec_name.substr(0, i);
7,031✔
404
            auto const it = sections_.find(cor_sec_name);
405
            if (it != sections_.end())
3,976✔
406
            {
407
                std::string const sub_sec_name = sec_name.substr(i + 1);
3,976✔
408
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
409
                return (*it).second.get_section(sub_sec_name);
3,976✔
410
            }
411

3,976✔
412
            std::string name(get_name());
413
            if (name.empty())
414
                name = "<root>";
415

×
416
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
417
                "section::get_section", "No such section ({}) in section: {}",
418
                sec_name, name);
×
419
        }
420

421
        auto const it = sections_.find(sec_name);
422
        if (it != sections_.end())
423
            return &((*it).second);
424

3,055✔
425
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section",
3,055✔
426
            "No such section ({}) in section: {}", sec_name, get_name());
427
    }
×
428

429
    void section::add_entry(std::unique_lock<mutex_type>& l,
430
        std::string const& fullkey, std::string const& key, std::string val)
431
    {
24,958✔
432
        // first expand the full property name in the value (avoids infinite recursion)
433
        expand_only(l, val, static_cast<std::string::size_type>(-1),
434
            get_full_name() + "." + key);
435

24,958✔
436
        std::string::size_type const i = key.find_last_of('.');
49,916✔
437
        if (i != std::string::npos)
438
        {
439
            section* current = root_;
24,958✔
440

441
            // make sure all sections in key exist
122✔
442
            std::string const sec_name = key.substr(0, i);
443

444
            std::string::size_type pos = 0;
122✔
445
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
446
                std::string::npos != pos1;
447
                pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
122✔
448
            {
336✔
449
                current = current->add_section_if_new(
214✔
450
                    l, sec_name.substr(pos, pos1 - pos));
451
            }
214✔
452

428✔
453
            current = current->add_section_if_new(l, sec_name.substr(pos));
454

455
            // now add this entry to the section
244✔
456
            current->add_entry(l, fullkey, key.substr(i + 1), val);
457
        }
458
        else
244✔
459
        {
460
            auto const it = entries_.find(key);
461
            if (it != entries_.end())
462
            {
463
                auto& e = it->second;
24,836✔
464
                e.first = HPX_MOVE(val);
465
                if (!e.second.empty())
466
                {
10,137✔
467
                    std::string const value = e.first;
10,137✔
468
                    entry_changed_func const f = e.second;
469

470
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
471
                    f(fullkey, value);
472
                }
473
            }
474
            else
475
            {
476
                // just add this entry to the section
477
                entries_[key] = entry_type(val, entry_changed_func());
478
            }
479
        }
29,398✔
480
    }
481

482
    void section::add_entry(std::unique_lock<mutex_type>& l,
24,958✔
483
        std::string const& fullkey, std::string const& key,
484
        entry_type const& val)
242,848✔
485
    {
486
        std::string::size_type const i = key.find_last_of('.');
487
        if (i != std::string::npos)
488
        {
489
            section* current = root_;
242,848✔
490

491
            // make sure all sections in key exist
×
492
            std::string const sec_name = key.substr(0, i);
493

494
            std::string::size_type pos = 0;
×
495
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
496
                std::string::npos != pos1;
497
                pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
×
498
            {
×
499
                current = current->add_section_if_new(
×
500
                    l, sec_name.substr(pos, pos1 - pos));
501
            }
×
502

×
503
            current = current->add_section_if_new(l, sec_name.substr(pos));
504

505
            // now add this entry to the section
×
506
            current->add_entry(l, fullkey, key.substr(i + 1), val);
507
        }
508
        else
×
509
        {
510
            auto const it = entries_.find(key);
511
            if (it != entries_.end())
512
            {
513
                auto& second = it->second;
242,848✔
514
                second = val;
515
                if (!second.second.empty())
516
                {
517
                    std::string const value = second.first;
×
518
                    entry_changed_func const f = second.second;
519

520
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
521
                    f(fullkey, value);
522
                }
523
            }
524
            else
525
            {
526
                // just add this entry to the section
527
                std::pair<entry_map::iterator, bool> const p =
528
                    entries_.emplace(key, val);
529
                HPX_ASSERT(p.second);
530

242,848✔
531
                auto const& second = p.first->second;
532
                if (!second.second.empty())
533
                {
534
                    std::string const k = p.first->first;
242,848✔
535
                    std::string const value = second.first;
536
                    entry_changed_func const f = second.second;
537

538
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
539
                    f(k, value);
540
                }
541
            }
542
        }
543
    }
544

545
    ///////////////////////////////////////////////////////////////////////////////
242,848✔
546
    template <typename F1, typename F2>
547
    class compose_callback_impl
548
    {
549
    public:
×
550
        template <typename A1, typename A2>
551
        compose_callback_impl(A1&& f1, A2&& f2)
552
          : f1_(HPX_FORWARD(A1, f1))
553
          , f2_(HPX_FORWARD(A2, f2))
×
554
        {
555
        }
556

557
        void operator()(std::string const& k, std::string const& v) const
×
558
        {
559
            f1_(k, v);
×
560
            f2_(k, v);
561
        }
562

563
    private:
×
564
        F1 f1_;
565
        F2 f2_;
566
    };
567

568
    template <typename F1, typename F2>
569
    static HPX_FORCEINLINE
570
        hpx::function<void(std::string const&, std::string const&)>
571
        compose_callback(F1&& f1, F2&& f2)
572
    {
573
        if (!f1)
574
            return HPX_FORWARD(F2, f2);
575
        else if (!f2)
12✔
576
            return HPX_FORWARD(F1, f1);
577

12✔
578
        // otherwise create a combined callback
579
        using result_type =
580
            compose_callback_impl<std::decay_t<F1>, std::decay_t<F2>>;
581
        return result_type(HPX_FORWARD(F1, f1), HPX_FORWARD(F2, f2));
582
    }
583

×
584
    void section::add_notification_callback(std::unique_lock<mutex_type>& l,
585
        std::string const& key, entry_changed_func const& callback)
586
    {
24✔
587
        std::string::size_type const i = key.find_last_of('.');
588
        if (i != std::string::npos)
589
        {
590
            section* current = root_;
24✔
591

592
            // make sure all sections in key exist
12✔
593
            std::string const sec_name = key.substr(0, i);
594

595
            std::string::size_type pos = 0;
12✔
596
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
597
                std::string::npos != pos1;
598
                pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
12✔
599
            {
36✔
600
                current = current->add_section_if_new(
24✔
601
                    l, sec_name.substr(pos, pos1 - pos));
602
            }
24✔
603

48✔
604
            current = current->add_section_if_new(l, sec_name.substr(pos));
605

606
            // now add this entry to the section
12✔
607
            current->add_notification_callback(l, key.substr(i + 1), callback);
608
        }
609
        else
24✔
610
        {
611
            // just add this entry to the section
612
            auto const it = entries_.find(key);
613
            if (it != entries_.end())
614
            {
615
                it->second.second =
12✔
616
                    compose_callback(callback, it->second.second);
617
            }
618
            else
24✔
619
            {
620
                entries_[key] = entry_type("", callback);
621
            }
622
        }
×
623
    }
624

625
    bool section::has_entry(
24✔
626
        std::unique_lock<mutex_type>& l, std::string const& key) const
627
    {
44,304✔
628
        std::string::size_type const i = key.find('.');
629
        if (i != std::string::npos)
630
        {
44,304✔
631
            std::string const sub_sec = key.substr(0, i);
44,304✔
632
            if (has_section(l, sub_sec))
633
            {
1✔
634
                std::string const sub_key = key.substr(i + 1, key.size() - i);
1✔
635
                auto const cit = sections_.find(sub_sec);
636
                HPX_ASSERT(cit != sections_.end());
1✔
637
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
638
                return (*cit).second.has_entry(sub_key);    //-V783
639
            }
640
            return false;
1✔
641
        }
642
        return entries_.find(key) != entries_.end();
643
    }
644

44,303✔
645
    std::string section::get_entry(
646
        std::unique_lock<mutex_type>& l, std::string const& key) const
647
    {
3,800✔
648
        if (std::string::size_type const i = key.find('.');
649
            i != std::string::npos)
650
        {
3,800✔
651
            std::string const sub_sec = key.substr(0, i);
652
            if (has_section(l, sub_sec))
653
            {
769✔
654
                std::string const sub_key = key.substr(i + 1, key.size() - i);
769✔
655
                auto const cit = sections_.find(sub_sec);
656
                HPX_ASSERT(cit != sections_.end());
769✔
657
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
658
                return (*cit).second.get_entry(sub_key);    //-V783
659
            }
660

769✔
661
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry",
662
                "No such key ({}) in section: {}", key, get_name());
663
        }
×
664

665
        if (entries_.find(key) != entries_.end())
666
        {
667
            auto const cit = entries_.find(key);
3,031✔
668
            HPX_ASSERT(cit != entries_.end());
669
            return expand(l, (*cit).second.first);    //-V783
670
        }
671

6,062✔
672
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry",
673
            "No such section ({}) in section: {}", key, get_name());
674
    }
×
675

676
    std::string section::get_entry(std::unique_lock<mutex_type>& l,
677
        std::string const& key, std::string const& default_val) const
678
    {
17,239✔
679
        typedef std::vector<std::string> string_vector;
680

681
        string_vector split_key;
682
        hpx::string_util::split(
683
            split_key, key, hpx::string_util::is_any_of("."));
17,239✔
684

17,239✔
685
        std::string const sk = split_key.back();
17,239✔
686
        split_key.pop_back();
687

688
        section const* cur_section = this;
689
        for (auto const& iter : split_key)
690
        {
691
            auto next = cur_section->sections_.find(iter);
35,503✔
692
            if (cur_section->sections_.end() == next)
693
                return expand(l, default_val);
694
            cur_section = &next->second;
18,392✔
695
        }
256✔
696

18,264✔
697
        auto const entry = cur_section->entries_.find(sk);
698
        if (cur_section->entries_.end() == entry)
699
            return expand(l, default_val);
700

17,111✔
701
        return expand(l, entry->second.first);
3,600✔
702
    }
703

30,622✔
704
    inline void indent(int ind, std::ostream& strm)
17,239✔
705
    {
706
        for (int i = 0; i < ind; ++i)
707
            strm << "  ";
708
    }
×
709

×
710
    void section::dump(int ind) const
711
    {
712
        return dump(ind, std::cout);
×
713
    }
714

×
715
    void section::dump(int ind, std::ostream& strm) const
716
    {
717
        std::unique_lock<mutex_type> l(mtx_);
×
718

719
        bool header = false;
×
720
        if (0 == ind)
721
            header = true;
722

×
723
        ++ind;
724
        if (header)
725
        {
×
726
            if (get_root() == this)
727
            {
728
                strm << "============================\n";
×
729
            }
730
            else
×
731
            {
732
                strm << "============================[\n"
733
                     << get_name() << "\n"
734
                     << "]\n";
735
            }
×
736
        }
×
737

738
        auto const eend = entries_.end();
739
        for (auto i = entries_.begin(); i != eend; ++i)
740
        {
741
            indent(ind, strm);
×
742

743
            auto& second = i->second;
744
            std::string const expansion = expand(l, second.first);
745

746
            // Check if the expanded entry is different from the actual entry.
×
747
            if (expansion != second.first)
748
            {
749
                // If the expansion is different from the real entry, then print
×
750
                // it out.
751
                strm << "'" << i->first << "' : '" << second.first << "' -> '"
752
                     << expansion << "'\n";
753
            }
754
            else
×
755
            {
756
                strm << "'" << i->first << "' : '" << second.first << "'\n";
757
            }
758
        }
×
759

760
        auto const send = sections_.end();
761
        for (auto i = sections_.begin(); i != send; ++i)
762
        {
763
            indent(ind, strm);
×
764
            strm << "[" << i->first << "]\n";
765
            (*i).second.dump(ind, strm);
766
        }
×
767

×
768
        if (header)
769
            strm << "============================\n";
770

×
771
        strm << std::flush;
×
772
    }
773

774
    void section::merge(std::string const& filename)
×
775
    {
776
        section tmp(filename, root_);
×
777
        merge(tmp);
778
    }
×
779

×
780
    void section::merge(section& second)
×
781
    {
782
        std::unique_lock<mutex_type> l(mtx_);
×
783

784
        // merge entries: keep own entries, and add other entries
×
785
        entry_map const& s_entries = second.get_entries();
786
        auto const end = s_entries.end();
787
        for (auto i = s_entries.begin(); i != end; ++i)
788
            entries_[i->first] = i->second;
789

×
790
        // merge subsection known in first section
×
791
        auto const send = sections_.end();
792
        for (auto i = sections_.begin(); i != send; ++i)
793
        {
794
            // is there something to merge with?
×
795
            if (second.has_section(l, i->first))
796
                i->second.merge(second.sections_[i->first]);
797
        }
×
798

×
799
        // merge subsection known in second section
800
        section_map s = second.get_sections();
801
        auto const secend = s.end();
802
        for (auto i = s.begin(); i != secend; ++i)
803
        {
804
            // if THIS knows the section, we already merged it above
×
805
            if (!has_section(l, i->first))
806
            {
807
                // it is not known here, so we can't merge, but have to add it.
×
808
                add_section(l, i->first, i->second, get_root());
809
            }
810
        }
×
811
    }
812

813
    /////////////////////////////////////////////////////////////////////////////////
×
814
    void section::line_msg(std::string msg, std::string const& file, int lnum,
815
        std::string const& line) const
816
    {
×
817
        msg += " " + file;
818
        if (lnum > 0)
819
            msg += ": line " + std::to_string(lnum);
×
820
        if (!line.empty())
×
821
            msg += " (offending entry: " + line + ")";
×
822

×
823
        HPX_THROW_EXCEPTION(hpx::error::no_success, "section::line_msg", msg);
×
824
    }
825

×
826
    ///////////////////////////////////////////////////////////////////////////////
827
    // find the matching closing brace starting from 'begin', escaped braces will
828
    // be un-escaped
829
    inline std::string::size_type find_next(char const* ch, std::string& value,
830
        std::string::size_type begin = static_cast<std::string::size_type>(-1))
831
    {
49,832✔
832
        std::string::size_type end = value.find_first_of(ch, begin + 1);
833
        while (end != std::string::npos)
834
        {
49,832✔
835
            if (end != 0 && value[end - 1] != '\\')
49,832✔
836
                break;
837
            value = detail::replace_substr(value, end - 1, 2, ch);
38,388✔
838
            end = value.find_first_of(ch, end);
839
        }
×
840
        return end;
841
    }
842

49,832✔
843
    ///////////////////////////////////////////////////////////////////////////////
844
    void section::expand(std::unique_lock<mutex_type>& l, std::string& value,
845
        std::string::size_type begin) const
846
    {
23,509✔
847
        std::string::size_type p = value.find_first_of('$', begin + 1);
848
        while (p != std::string::npos && value.size() - 1 != p)
849
        {
23,509✔
850
            if ('[' == value[p + 1])
28,284✔
851
                expand_bracket(l, value, p);
852
            else if ('{' == value[p + 1])
4,775✔
853
                expand_brace(l, value, p);
3,239✔
854
            p = value.find_first_of('$', p + 1);
1,536✔
855
        }
×
856
    }
857

858
    void section::expand_bracket(std::unique_lock<mutex_type>& l,
23,509✔
859
        std::string& value, std::string::size_type begin) const
860
    {
3,239✔
861
        // expand all keys embedded inside this key
862
        expand(l, value, begin);
863

864
        // now expand the key itself
3,239✔
865
        std::string::size_type const end = find_next("]", value, begin + 1);
866
        if (end != std::string::npos)
867
        {
3,239✔
868
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
3,239✔
869
            std::string::size_type const colon = find_next(":", to_expand);
870
            if (colon == std::string::npos)
3,239✔
871
            {
3,239✔
872
                value = detail::replace_substr(value, begin, end - begin + 1,
3,239✔
873
                    root_->get_entry(l, to_expand, std::string()));
874
            }
3,239✔
875
            else
9,717✔
876
            {
877
                value = detail::replace_substr(value, begin, end - begin + 1,
878
                    root_->get_entry(l, to_expand.substr(0, colon),
879
                        to_expand.substr(colon + 1)));
×
880
            }
×
881
        }
×
882
    }
883

884
    void section::expand_brace(std::unique_lock<mutex_type>& l,
3,239✔
885
        std::string& value, std::string::size_type begin) const
886
    {
×
887
        // expand all keys embedded inside this key
888
        expand(l, value, begin);
889

890
        // now expand the key itself
×
891
        std::string::size_type const end = find_next("}", value, begin + 1);
892
        if (end != std::string::npos)
893
        {
×
894
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
×
895
            std::string::size_type const colon = find_next(":", to_expand);
896
            if (colon == std::string::npos)
×
897
            {
×
898
                char const* env = std::getenv(to_expand.c_str());
×
899
                value = detail::replace_substr(
900
                    value, begin, end - begin + 1, nullptr != env ? env : "");
×
901
            }
×
902
            else
×
903
            {
904
                char* env = std::getenv(to_expand.substr(0, colon).c_str());
905
                value = detail::replace_substr(value, begin, end - begin + 1,
906
                    nullptr != env ? std::string(env) :
×
907
                                     to_expand.substr(colon + 1));
×
908
            }
×
909
        }
×
910
    }
911

912
    std::string section::expand(
×
913
        std::unique_lock<mutex_type>& l, std::string value) const
914
    {
20,270✔
915
        expand(l, value, static_cast<std::string::size_type>(-1));
916
        return value;
917
    }
20,270✔
918

20,270✔
919
    ///////////////////////////////////////////////////////////////////////////////
920
    void section::expand_only(std::unique_lock<mutex_type>& l,
921
        std::string& value, std::string::size_type begin,
922
        std::string const& expand_this) const
46,635✔
923
    {
924
        std::string::size_type p = value.find_first_of('$', begin + 1);
925
        while (p != std::string::npos && value.size() - 1 != p)
926
        {
46,635✔
927
            if ('[' == value[p + 1])
80,600✔
928
                expand_bracket_only(l, value, p, expand_this);
929
            else if ('{' == value[p + 1])
33,965✔
930
                expand_brace_only(l, value, p, expand_this);
7,821✔
931
            p = value.find_first_of('$', p + 1);
26,144✔
932
        }
13,856✔
933
    }
934

935
    void section::expand_bracket_only(std::unique_lock<mutex_type>& l,
46,635✔
936
        std::string& value, std::string::size_type begin,
937
        std::string const& expand_this) const
7,821✔
938
    {
939
        // expand all keys embedded inside this key
940
        expand_only(l, value, begin, expand_this);
941

942
        // now expand the key itself
7,821✔
943
        std::string::size_type const end = find_next("]", value, begin + 1);
944
        if (end != std::string::npos)
945
        {
7,821✔
946
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
7,821✔
947
            std::string::size_type const colon = find_next(":", to_expand);
948
            if (colon == std::string::npos)
7,821✔
949
            {
7,821✔
950
                if (to_expand == expand_this)
7,821✔
951
                {
952
                    value =
7,821✔
953
                        detail::replace_substr(value, begin, end - begin + 1,
954
                            root_->get_entry(l, to_expand, std::string()));
955
                }
×
956
            }
×
957
            else if (to_expand.substr(0, colon) == expand_this)
958
            {
959
                value = detail::replace_substr(value, begin, end - begin + 1,
×
960
                    root_->get_entry(l, to_expand.substr(0, colon),
961
                        to_expand.substr(colon + 1)));
×
962
            }
×
963
        }
×
964
    }
965

966
    void section::expand_brace_only(std::unique_lock<mutex_type>& l,
7,821✔
967
        std::string& value, std::string::size_type begin,
968
        std::string const& expand_this) const
13,856✔
969
    {
970
        // expand all keys embedded inside this key
971
        expand_only(l, value, begin, expand_this);
972

973
        // now expand the key itself
13,856✔
974
        std::string::size_type const end = find_next("}", value, begin + 1);
975
        if (end != std::string::npos)
976
        {
13,856✔
977
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
13,856✔
978
            std::string::size_type const colon = find_next(":", to_expand);
979
            if (colon == std::string::npos)
13,856✔
980
            {
13,856✔
981
                char const* env = std::getenv(to_expand.c_str());
13,856✔
982
                value = detail::replace_substr(
983
                    value, begin, end - begin + 1, nullptr != env ? env : "");
384✔
984
            }
1,152✔
985
            else
384✔
986
            {
987
                char* env = std::getenv(to_expand.substr(0, colon).c_str());
988
                value = detail::replace_substr(value, begin, end - begin + 1,
989
                    nullptr != env ? std::string(env) :
13,472✔
990
                                     to_expand.substr(colon + 1));
13,472✔
991
            }
26,944✔
992
        }
13,472✔
993
    }
994

995
    std::string section::expand_only(std::unique_lock<mutex_type>& l,
13,856✔
996
        std::string value, std::string const& expand_this) const
997
    {
×
998
        expand_only(
999
            l, value, static_cast<std::string::size_type>(-1), expand_this);
1000
        return value;
×
1001
    }
1002

×
1003
    ///////////////////////////////////////////////////////////////////////////////
1004
    template <typename Archive>
1005
    void section::save(Archive& ar, unsigned int const /* version */) const
1006
    {
1007
        ar << name_;
×
1008
        ar << parent_name_;
1009

×
1010
        std::uint64_t size = entries_.size();
×
1011
        ar << size;
1012
        for (auto const& val : entries_)
1013
        {
1014
            ar << val.first;
×
1015
        }
1016

×
1017
        ar << sections_;
1018
    }
1019

×
1020
    template <typename Archive>
×
1021
    void section::load(Archive& ar, unsigned int const /* version */)
1022
    {
1023
        ar >> name_;
×
1024
        ar >> parent_name_;
1025

×
1026
        std::uint64_t size;
×
1027
        ar >> size;    //-V128
1028

1029
        entries_.clear();
1030
        for (std::size_t i = 0; i < size; ++i)
1031
        {
1032
            using value_type = entry_map::value_type;
×
1033

1034
            value_type v;
1035
            ar >> const_cast<std::string&>(v.first);
1036
            entries_.insert(entries_.end(), HPX_MOVE(v));
1037
        }
1038

1039
        ar >> sections_;
1040

1041
        set_root(this, true);    // make this the current root
×
1042
    }
1043

×
1044
    // explicit instantiation for the correct archive types
×
1045
    template HPX_CORE_EXPORT void section::save(
1046
        serialization::output_archive&, unsigned int const version) const;
1047

1048
    template HPX_CORE_EXPORT void section::load(
1049
        serialization::input_archive&, unsigned int const version);
1050
}    // namespace hpx::util
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